Shapes and rotation

Discussion forum for all Windows batch related topics.

Moderator: DosItHelp

Post Reply
Message
Author
IcarusLives
Posts: 161
Joined: 17 Jan 2016 23:55

Shapes and rotation

#1 Post by IcarusLives » 01 Apr 2018 22:59

Hello all ^-^

Image Image

I would mostly like to share (what you all probably already know) but I'm quite proud of it because I took the time to experiment, and learn all of this on my own. I soon come to find out that I've simulated the "mid-point circle" algorithm, but I've applied the math to create shapes of all sides (except circles, being the absolute most trivial).

A circle would be simple.

Code: Select all

x=20 * !cos(x):x=angle! + 50"
y=20 * !sin(x):x=angle! + 50"
Expanding my knowledge of this fundamental for circles, I considered dividing up the degrees of a circle, and plotting them evening.

Code: Select all

360/sides
But the experimenting didn't stop there. I wanted to not only get different shapes, but I wanted to expand or shrink their size, and I wanted to rotate them, and I wanted them colorful.

I was using Bresenham's Line algorithm as a function before, but found it's performance to be so slow it made me cringe, so I implemented as a macro. This macro has usage commented in the script.

So this is the script I've come up with! CHECK THE "CHANGE ME!!!!" on line 69

I really hope you enjoy!

Code: Select all

@echo off & setlocal enableDelayedExpansion
mode 100,100

set ^"LF=^

^" Above empty line is required - do not remove
set ^"\n=^^^%LF%%LF%^%LF%%LF%^^"

rem capture ESC for VT100 %plot% macro. %line% ultilizes %plot%
for /F %%a in ('echo prompt $E^| cmd') do set "ESC=%%a"

    set "_SIN=a-a*a/1920*a/312500+a*a/1920*a/15625*a/15625*a/2560000-a*a/1875*a/15360*a/15625*a/15625*a/16000*a/44800000"
    set "SIN(x)=(a=(x * 31416 / 180)%%62832, c=(a>>31|1)*a, a-=(((c-47125)>>31)+1)*((a>>31|1)*62832)  +  (-((c-47125)>>31))*( (((c-15709)>>31)+1)*(-(a>>31|1)*31416+2*a)  ), %_SIN%) / 10000"
    set "COS(x)=(a=(15708 - x * 31416 / 180)%%62832, c=(a>>31|1)*a, a-=(((c-47125)>>31)+1)*((a>>31|1)*62832)  +  (-((c-47125)>>31))*( (((c-15709)>>31)+1)*(-(a>>31|1)*31416+2*a)  ), %_SIN%) / 10000"
    set "_SIN="

rem %plot% x y COLOR(0-255) COLOR(0-255) CHAR
set plot=for %%# in (1 2) do if %%#==2 ( for /f "tokens=1-5" %%1 in ("^!args^!") do (%\n%
  set "screen=^!screen^!!esc![%%2;%%1H!esc![38;5;%%3m!esc![48;5;%%4m%%~5!esc![0m"%\n%
)) else set args=

rem %line% Bresenham Line Algorithm for all slopes
rem I will comment this later.. Sorry

rem USAGE:
rem %line% x1 y1 x2 y2 CHAR COLOR(0-255)
set line=for %%# in (1 2) do if %%#==2 ( for /f "tokens=1-6" %%1 in ("^!args^!") do (%\n%
	if "%%~6" equ "" ( set "hue=30" ) else ( set "hue=%%~6")%\n%
	set /a "xa=%%~1", "ya=%%~2", "xb=%%~3", "yb=%%~4", "dx=%%~3 - %%~1", "dy=%%~4 - %%~2"%\n%
	for /f "tokens=1-2" %%6 in ("^!dx^! ^!dy^!") do (%\n%
		if %%~7 lss 0 ( set /a "dy=-%%~7", "stepy=-1" ) else ( set "stepy=1" )%\n%
		if %%~6 lss 0 ( set /a "dx=-%%~6", "stepx=-1" ) else ( set "stepx=1" )%\n%
		set /a "dx<<=1", "dy<<=1"%\n%
	)%\n%
	for /f "tokens=1-9" %%a in ("^!dx^! ^!dy^! ^!xa^! ^!xb^! ^!ya^! ^!yb^! ^!stepx^! ^!stepy^! ^!hue^!") do (%\n%
		if %%~a gtr %%~b (%\n%
			set /a "fraction=%%~b - (%%~a >> 1)"%\n%
			for /l %%x in (%%~c,%%~g,%%~d) do (%\n%
				for /f "tokens=1" %%6 in ("^!fraction^!") do if %%~6 geq 0 set /a "ya+=%%~h", "fraction-=%%~a"%\n%
				set /a "fraction+=%%~b"%\n%
				for /f "tokens=1" %%6 in ("^!ya^!") do (%\n%
					if 0 leq %%x if %%x lss 199 if 0 leq %%~6 if %%~6 lss 199 ^!plot^! %%x %%~6 %%i 0 %%~5%\n%
				)%\n%
			)%\n%
		) else (%\n%
			set /a "fraction=%%~a - (%%~b >> 1)"%\n%
			for /l %%y in (%%~e,%%~h,%%~f) do (%\n%
				for /f "tokens=1" %%6 in ("^!fraction^!") do if %%~6 geq 0 set /a "xa+=%%~g", "fraction-=%%~b"%\n%
				set /a "fraction+=%%~a"%\n%
				for /f "tokens=1" %%6 in ("^!xa^!") do (%\n%
					if 0 leq %%~6 if %%~6 lss 199 if 0 leq %%y if %%y lss 199 ^!plot^! %%~6 %%y %%i 0 %%~5%\n%
				)%\n%
			)%\n%
		)%\n%
	)%\n%
)) else set args=

:: Hide the cursor
<nul set /p "=!esc![?25l"
cls







REM CHANGE ME --------
	set /a "sides=5"
REM ------------------

set /a "x=50", "y=50", "s=-3"
set /a "angle=360 / sides"

for /l %%a in (0,1,16) do (

	set /a "a0+=%%a", "s+=3", "hue=%%a %% 255"
	
	for /l %%c in (1,1,%sides%) do (
		set /a "b=%%c - 1"
		for /f "tokens=1" %%b in ("!b!") do set /a "a%%c=!a%%b! + angle"
		set /a "x%%c=s * !cos(x):x=a%%c! + x", "y%%c=s * !sin(x):x=a%%c! + y"
	)
	set /a "c=sides + 1" & set /a "x!c!=x1", "y!c!=y1"
	
	for /l %%c in (1,1,%sides%) do (
		set /a "d=%%c + 1"
		for /f "tokens=1" %%b in ("!d!") do %line% !x%%c! !y%%c! !x%%b! !y%%b! Û !hue!
	)
	
	<nul set /p "=!screen!" & set "screen="
)
pause >nul & exit
For a beautiful phyllotaxis, you can change the SIDES to 20, and change LINE 91 to

Code: Select all

for /f "tokens=1" %%b in ("!d!") do %plot% !x%%c! !y%%c! !hue! 0 Û
instead of

Code: Select all

for /f "tokens=1" %%b in ("!d!") do %line% !x%%c! !y%%c! !x%%b! !y%%b! Û !hue!
Image

T3RRY
Posts: 243
Joined: 06 May 2020 10:14

Re: Shapes and rotation

#2 Post by T3RRY » 10 Jan 2023 21:16

Found this gem while doing some research on Bresenham's Line algorithm for a Batch tower defense game I'm working on.

Love your work with the Line and Plot macro's, but the game I'm making demanded a bit more in the way of efficiency, So I needed to refactor the macro.
There was a number of superfluous for loops in the nest I was able to do away with, and I built the plotting into the macro to avoid the extra loops that captured arguments we already have. In it's current form, this version of the macro is ~ 38% faster than your original in the same usage conditions [ 79/100th of a second vs 128/100ths ].

Here's what I came up with. A couple of extra features have been added in as well.
- A New mandatory argument added - Cell Spacing Interval. define every n characters to the line. 1 = Solid line
- Dumping of the screen variable after it's length exceeds 1023 characters
- Support for the provision of multiple line arguments in a macro 'call'

Argument Order: x1 y1 x2 y2 ForegroundCol CellSpacing Character [/C /O /R /N /P /A /D:Integer]]
- /C toggles cursor off /on before and after output
- The Line can be output immediately after definition by providing /O
- The screen variable can be reset on expansion of the macro by providing /R
- /N Disables automated dump of Screen variable after line exceeds 1023 characters
- /P Preserves the Screen variable after automatic dump
- The line can be animated [output each cell with a minor delay] by providing /A
- The delay timing can be modified by providing an integer for the number of For /l rem loops, IE: /D:5000
- /D must be the last Switch used. Use of /D makes Animation Implicit. IE, /D implies /A state without having to use /A

Code: Select all

@Echo off

CHCP 65001 > nul

CLS
Rem requires Windows 10

(Set \n=^^^

%= \n linefeed for macro definition. Do not modify =%)

	for /F %%a in ('Echo(prompt $E^| cmd')Do Set \E=%%a

	REM Bresenham's line algorithm implementation
	REM refactored from Line and Plot macro's by IcarusLives As seen at https://www.dostips.com/forum/viewtopic.php?t=8469#p56154
	REM this version is not escaped for definition with Delayed expansion enabled.
	If "!!" == "" (
		Echo(DelayedExpansion not permitted at this time
		Pause > nul
		Exit /B 1
	)

	Set ^"DQ=""
	Set CompArg=^!Argset:~0,1^!^!Argset:~-1^!

	Set BuildLine=For %%n in (1 2)Do if %%n==2 (%\n%
		If "!ArgSet:~0,1!"==" " Set "ArgSet=!ArgSet:~1!"%\n%
		Set ^"ArgSet=!ArgSet:"={DQ}!"%\n%
		If not "!ArgSet:~0,4!!ArgSet:~-4!"=="{DQ}{DQ}" Set "ArgSet={DQ}!ArgSet!{DQ}"%\n%
		Set ^"ArgSet=!ArgSet:{DQ}="!"%\n%
		For %%A in (!ArgSet!) Do (%\n%
			Set "BuildLineArgs=%%~A"%\n%
		2^> nul (%\n: Optional Args "/O"; Outputs the line after build. "/R"; Resets the Screen variable Prior to Build; /A Animate the drawing of the line during Build. =%
				For /F "tokens=1-7 Delims= " %%G in ("!BuildLineArgs!")Do (%\n:Args - x1 y1 x2 y2 ForegroundCol CellSpacing Character [/C /O /R /P /A /N /D:Integer] =%
					set /a "stepY=1","stepX=1","xa=%%G", "ya=%%H", "xb=%%I", "yb=%%J", "dx=xb - xa","dy=yb - ya","FGc=%%K","interval=0","iMOD=%%L","Cout=0","Anim=0","aDelay=2500"%\n%
					Set "Screen=!Screen!!\E![38;5;!FGc!m"%\n%
					Set Char=^^%%M%\n%
				)%\n%
				If not "!BuildlineArgs:/O=!"=="!BuildLineArgs!" Set "Cout=1"%\n%
				If not "!BuildlineArgs:/D:=!"=="!BuildLineArgs!" (%\n%
					Set /A "aDelay=!BuildlineArgs:*/D:=!"%\n%
					Set "Anim=1"%\n%
				)%\n%
				If not "!BuildlineArgs:/A=!"=="!BuildLineArgs!" Set "Anim=1"%\n%
				If not "!BuildlineArgs:/R=!"=="!BuildLineArgs!" Set "Screen=!\E![38;5;!FGc!m"%\n%
				If not "!BuildlineArgs:/C=!"=="!BuildLineArgs!" (%\n%
					Set "Cursor=1"%\n%
					Set "Screen=%\E%[?25l!Screen!"%\n%
				)%\n%
				if !dy! lss 0 set /a "dy=-dy", "stepy=-1"%\n%
				if !dx! lss 0 set /a "dx=-dx", "stepx=-1"%\n%
				set /a "dx<<=1", "dy<<=1"%\n%
				if !dx! gtr !dy! (%\n%
					set /a "fraction=dy - (dx >> 1)"%\n%
					for /l %%x in (!xa!,!stepx!,!xb!) do (%\n%
						If !Fraction! geq 0 set /a "ya+=stepy", "fraction-=dx"%\n%
						Set /A "Interval=Interval %% !iMOD! + 1","fraction+=dy"%\n%
						If !Interval!==!iMOD! if 0 leq %%x if %%x lss 199 if 0 leq !ya! if !ya! lss 199 If !Interval!==!iMod! (%\n%
							set "Screen=!Screen!!\E![!ya!;%%xH!Char!"%\n%
							If !Anim!==1 (%\n%
								^<nul Set /P "=!\E![!ya!;%%xH!\E![38;5;!FGc!m!Char!!\E![0m"%\n%
								For /L %%i in (1 1 !aDelay!)Do REM Delay%\n%
					)	)	)%\n%
				) else (%\n%
					set /a "fraction=dx - (dy >> 1)"%\n%
					for /l %%y in (!ya!,!stepy!,!yb!) do (%\n%
						If !Fraction! geq 0 set /a "xa+=stepx", "fraction-=dy"%\n%
							Set /A "Interval=Interval %% !iMOD! + 1","fraction+=dx"%\n%
							If !Interval!==!iMOD! If 0 leq !xa! if !xa! lss 199 if 0 leq %%y if %%y lss 199 if 0 leq !xa! if !xy! lss 199 if 0 leq %%y if %%y lss 199 (%\n%
							set "Screen=!Screen!!\E![%%y;!xa!H!Char!"%\n%
							If !Anim!==1 (%\n%
								^<nul Set /P "=!\E![%%y;!xa!H!\E![38;5;!FGc!m!Char!!\E![0m"%\n%
								For /L %%i in (1 1 !aDelay!)Do REM Delay%\n%
					)	)	)%\n%
				)%\n%
				If !Cursor!==1 Set "Screen=!Screen!%\E%[?25h"%\n%
				If !Cout!==1 ^<nul Set /P "=!Screen!!\E![0m"%\n%
				If "!BuildLineArgs:/N=!"=="!BuildLineArgs!" If not "!Screen:~1023,1!"=="" (%\n: Dump the screen buffer if StrLen GEQ 1024 ~ optimal buffer size =%
					^<nul Set /P "=!Screen!%\E%[0m"%\n%
					If "!BuildLineArgs:/P=!"=="!BuildLineArgs!" Set "Screen="%\n: If not /P used to Preserve Screen 'buffer'. =%
				)%\n%
			)%\n%
		)%\n%
	)Else Set Argset=

    Setlocal EnableDelayedExpansion
    <nul Set /P "=%\E%[?25l"
    %BuildLine% 1 2 79 10 35 1 ^>
    %BuildLine% 1 6 79 6 31 2 .
    %BuildLine% 1 10 79 2 40 3 - /O
    %BuildLine% "1  1  80 1  235 2 ▓ /R","1  1  1  11 235 2 ▓","1  11 80 11 235 2 ▓","80 2  80 11 235 2 ▓ /O"

    %BuildLine% 1 12 80 12 1 1 _ /R /A 
    %BuildLine% 80 15 1 15 1 1 _ /A /P
    <nul Set /P "=!Screen:1m=10m!%\E%[?25h%\E%[14;1H!\E![0m"

    Pause
    <nul Set /P "=!\E![2E"
Endlocal & Exit /b 0

Post Reply