Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- #@gui ____<b>Map Projection</b>
- #-----------------------------
- ###############################
- ## EQUIRECTANGULAR ROTATION
- #@gmic rotate_equirectangular_map : roll angle, pitch angle, yaw angle, revert bool
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around three axises
- #@gui Rotate Equirectangular Map : rotate_equirectangular_map
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order in degrees.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch ("north and south") = float(0,-360,360)
- #@gui : Yaw ("east and west") = float(0,-360,360)
- #@gui : Revert rotations = bool(false)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- rotate_equirectangular_map :
- # Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0}
- # Black magic spell to make the preview look better???
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # Create new image, the ""-block is the mathematical 'function' that
- # determines the value of the output pixel wherever we are iterating
- -input 100%,100%,1,100%,"
- # Command parameters from the command line or the sliders.
- # Variables from outside the ""-block have to be outside the ""s.
- yaw="{$3}";
- pitch="{$2}";
- roll="{$1}";
- revert="{$4}";
- # Converting degrees into radians for the matrices later
- # Those minus signs are just a direction correction.
- alpha=-roll * pi / 180;
- beta=-pitch * pi / 180;
- gamma=-yaw * pi / 180;
- # Equirectangular coordinates into spherical radians coordinates
- # phi <- height
- # theta <- width
- # radius rho=1, we are always working with a unit sphere / globe with radius 1
- # The extra pi in "otheta=PI..." is to offset the axis towards the center of the image
- otheta=pi + (x/w)*2*pi;
- ophi=(y/h)*pi;
- rho=1;
- # Convert to Cartesian x, y, z, we can leave out rho=1
- # cx=rho*sin(ophi)*cos(otheta);
- # cy=rho*sin(ophi)*sin(otheta);
- # cz=rho*cos(ophi);
- cx=sin(ophi)*cos(otheta);
- cy=sin(ophi)*sin(otheta);
- cz=cos(ophi);
- # Do the transformation in Cartesian using rotation matrix maths magic
- if( revert==0,
- rotz=cz*( cos(alpha)*cos(beta) )
- + cy*( cos(alpha)*sin(beta)*sin(gamma) - sin(alpha)*cos(gamma) )
- + cx*( cos(alpha)*sin(beta)*cos(gamma) + sin(alpha)*sin(gamma) );
- roty=cz*( sin(alpha)*cos(beta) )
- + cy*( sin(alpha)*sin(beta)*sin(gamma) + cos(alpha)*cos(gamma) )
- + cx*( sin(alpha)*sin(beta)*cos(gamma) - cos(alpha)*sin(gamma) );
- rotx=cz*(-sin(beta))
- + cy*(cos(beta)*sin(gamma))
- + cx*(cos(beta)*cos(gamma)); ,
- # !!!!!!!!!!!!!!!! Reversion matrix??
- # small letter x = cos(x)
- # capital letter X = sin(x)
- # {{ a*b, -A*b, B }
- # { B*G*a+A*g, -A*B*G+a*g, -G*b }
- # { A*G-B*a*g, G*a+A*B*g, b*g }}
- ## Testing reversion
- rotz=cz*( cos(-alpha)*cos(-beta) )
- + cy*( -sin(-alpha)*cos(-beta) )
- + cx*( sin(-beta) );
- roty=cz*( sin(-beta)*sin(-gamma)*cos(-alpha) + sin(-alpha)*cos(-gamma) )
- + cy*( -sin(-alpha)*sin(-beta)*sin(-gamma) + cos(-alpha)*cos(-gamma) )
- + cx*( -sin(-gamma)*cos(-beta) );
- rotx=cz*(sin(-alpha)*sin(-gamma) - sin(-beta)*cos(-alpha)*cos(-gamma) )
- + cy*(sin(-gamma)*cos(-alpha) + sin(-alpha)*sin(-beta)*cos(-gamma) )
- + cx*(cos(-beta)*cos(-gamma));
- );
- # Convert the rotated point BACK into spherical coordinates
- # Atan2 is a special programming thing to do arctan, except better
- # It's got its own Wikipedia page
- ntheta=atan2(roty, rotx);
- nphi=acos( rotz / sqrt(rotx*rotx + roty*roty + rotz*rotz) );
- # Convert spherical coordinates almost straight back into
- # equirectangular pixel coordinates.
- x2=( (ntheta/pi/2)*w+w/2 );
- y2=(nphi/pi)*h;
- # I: from image #0 take the vector(pixel value) of x2,y2,z(=0)
- # "2": Cubic interpolation of pixels
- # "0": Boundary condition: if you hit "nothing", what do you do? N/A here.
- I(#0,x2,y2,0,2,1)"
- # Keep the last image generated ("k." = keep[-1] image index)
- keep[-1]
- ########################
- ## SINUSOIDAL
- #@gmic sinusoidal_map : yaw angle, pitch angle, roll angle, bgred, bggreen, bgblue, slices
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a sliced sinusoidal map
- #@gui Sinusoidal Map : sinusoidal_map
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a sinusoidal projection.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch ("north and south") = float(0,-360,360)
- #@gui : Yaw ("east and west") = float(0,-360,360)
- #@gui : Background color = color(128,128,128)
- #@gui : Background opacity (%) = float(100,0,100)
- #@gui : Slices = int(1,1,72)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- sinusoidal_map :
- # $1-3 Default to 0 degrees
- # $4-6 color(r,g,b) gives you three separate parameters instead of, say, a vector
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=0},${7=100} -check ${8=1}>=1
- slices=$8
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # Slice the rotated map image into vertical sections
- split x,$slices
- # Loop over each slice. $! = number of images in the image list
- repeat $!
- # No keyword: create an image. The ""-block is the mathematical function
- # whose result/return value at the end determines the value of the pixel
- # x, y we are iterating over.
- -input 100%,100%,1,100%,"
- # Background color
- bgr="{$4}";
- bgg="{$5}";
- bgb="{$6}";
- bgopacity="{$7}/100*255";
- # Half-accidental magical formula. Half-sin is used to center the coordinates somehow??
- halfsin=sin( (y/h)*pi )*w / 2;
- x2=(x+halfsin-w/2)/sin( y/h*pi);
- # y = y in this case, just use original y.
- # Check whether we're coloring inside or outside the sinusoidal shape
- if ( (x >= (w/2-halfsin) && x <= (w/2+halfsin) ),
- I(#"$>",x2,y,0,2,0),
- color=[bgr, bgg, bgb, bgopacity]);"
- # repeat-loop end
- done
- # Delete the old map, which was sliced up
- remove[0-{$slices-1}]
- # join all the rest (new) slices together in order on the x axis
- append x
- # Keep the last (. = [-1] image index) image generated
- keep[-1]
- #######################
- ## TRIANGULAR
- #@gmic triangular_projection : yaw angle, pitch angle, roll angle, bgred, bggreen, bgblue, slices
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a sliced triangular map.
- #@gmic : This is not the Collignon projection.
- #@gmic : It's a naive triangular interpolation.
- #@gui Triangular projection : triangular_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a naive rectilinear projection. This is not a Collignon projection, but a naive linear interpolation.")
- #@gui : note = note("When the width at the poles is 50%, this becomes the Eckert I projection. These projections are not equal-area nor do they have any other useful cartographical property.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch ("north and south") = float(0,-360,360)
- #@gui : Yaw ("east and west") = float(0,-360,360)
- #@gui : Background color = color(128,128,128)
- #@gui : Background opacity (%) = float(100,0,100)
- #@gui : Slices = int(1,1,72)
- #@gui : Width at the poles % = float(50,0,100)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- triangular_projection :
- # $1-3 Default to 0 degrees
- # $4-7 color(r,g,b) gives you three separate parameters instead of, say, a vector
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=0},${7=100} -check ${8=1}>=1" && "${9=5}>=0
- slices=$8
- magic=$9
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- # Background color
- bgr=$4;
- bgg=$5;
- bgb=$6;
- bgopacity={$7/100*255};
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # Slice the rotated map image into vertical sections
- split x,$slices
- # Input: create an image. The ""-block is the mathematical function
- # whose result/return value at the end determines the value of the pixel
- # x, y we are iterating over.
- -input 100%,100%,1,4,"
- startwidth="$magic";
- if( (y<=h/2),
- my=y,
- my=h-y);
- sc=startwidth/100;
- squish=w / lerp((w*sc), w, my/(h/2));
- shift=(w-squish*w)/2;
- X = squish * x +shift;
- Y=y;
- #debug normalisation values: cap at w so everything normalizes
- #result=[min(w,X),min(Y,w),0,w];"
- result=[X,Y,0,0];"
- # Loop over each slice. $! = number of images in the image list
- # Because the warp map is identical for each "slice" in this version
- # of the script / process, it doesn't need to generated for each slice,
- # so it's just reused. The sinusoidal script does an in-place operation
- # for each slice.
- repeat $slices
- # the $> is a loop index incrementing forwards (think i++).
- # if there was $< it would loop backwards (like i--)
- # but here we only need to use the one warp image at the very
- # end "[-1]" of the image stack
- -warp[$>] [-1],0,2,0
- done
- #DISPLACEMENT WARP
- # Delete the warp map, which was sliced up
- remove[-1]
- # join all the rest (new) slices together in order on the x axis
- #for debugging by normalizing and appending the warp field image
- #-normalize[-1] 0,255
- append x
- # generate blank image, then fill_color with bg-color
- -input 100%,100%,1,4,0
- -fill_color[-1] $bgr,$bgg,$bgb,$bgopacity
- reverse
- -blend alpha
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## CYLINDRICAL EQUAL AREA
- #@gmic cylindrical_equal_area : yaw angle, pitch angle, roll angle, standard_parallel angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a cylindrical equal area map.
- #@gui Cylindrical equal-area projection : cylindrical_equal_area
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a cylindrical equal-area projection.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch ("north and south") = float(0,-360,360)
- #@gui : Yaw ("east and west") = float(0,-360,360)
- #@gui : Standard parallels = float(45,0,80)
- #@gui : Named specializations = choice("[Standard parallels ↑]","Lambert 0° π:1","Behrmann 30°","Smyth/Craster ≈37°04\′17\″ 2:1","Trystan Edwards 37°24\′","Hobo-Dyer 37°30\′","Gall-Peters 45°","Balthasar 50°","Tobler ≈55°39\′14\″ 1:1","[Custom formula ↓]")
- #@gui : Custom formula = text{"acos(sqrt(1/pi))"}
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- cylindrical_equal_area :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0} -check ${4=45}<=80
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- # Standard parallells custom
- phi_input=$4
- # G'mic-style "array"
- if $5==1 phi0=0
- elif $5==2 phi0={30*pi/180}
- elif $5==3 phi0={acos(sqrt(2/pi))}
- elif $5==4 phi0={37.4*pi/180}
- elif $5==5 phi0={37.5*pi/180}
- elif $5==6 phi0={45*pi/180}
- elif $5==7 phi0={50*pi/180}
- elif $5==8 phi0={acos(sqrt(1/pi))}
- elif $5==9 phi0={$6}
- # use Standards parallels input
- else phi0={$phi_input*pi/180}
- endif
- # phi0 is the input parameter Standard parallels in radians
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # width of original map
- nw={0,w}
- # height of original map
- nh={0,h}
- # Determine the dimensions of the output projection by using
- # the ratio of w:h as give by Wikipedia
- # https://en.wikipedia.org/wiki/Cylindrical_equal-area_projection
- # w:h = pi*(cos phi_0)²
- W={$nw*pi*cos($phi0)^2}
- H={$nw}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input $W,$H,1,4,"
- phi0="$phi0";
- pi2=2*pi;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2;
- cy=y-h/2;
- # Turn them into radians??
- cx = (cx/w *pi2);
- cy = (cy/w *pi2);
- # Somehow I cancelled out the formula for nX, it's
- # now part of the output image width formula above????
- nX = cx;
- # I don't know! I don't know! But this formula works!!
- nY = asin(cy * cos(phi0)^2);
- # Here's the magic trick: the X and Y coordinates we are
- # calculating are not about where something goes, it's about
- # where something COMES FROM. Because of the way G'mic makes
- # you think about 'filters', you have to invert the transformation
- # direction: you look at the OUTPUT images' x and y coordinates,
- # then figure out where *from* that values has to come from.
- # Basically, we're taking the output and calculating it in reverse,
- # so that we get equirectangular (=spherical) coordinates back.
- # That's why instead of calculating with SINE, which is the way you
- # do it forward, we calculate with ARCSINE, which is backwards.
- # This is the number one reason why doing this stuff in G'mic is torture.
- # Check out the formulas in
- # https://mathworld.wolfram.com/CylindricalEqual-AreaProjection.html
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2) ;
- Y=oh/2 + (oh * nY/pi) ;
- if( (nX>=-pi && nX<=pi && nY>=-pi/2 && nY<=pi/2),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- -autocrop[1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## LAMBERT AZIMUTHAL
- #@gmic lambert_azimuthal_projection : yaw angle, pitch angle, roll angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a Lambert azimuthal equal area map.
- #@gui Lambert Azimuthal Equal-Area : lambert_azimuthal_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a Lambert Azimuthal Equal-Area map.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Standard parallel = float(0,-90,90)
- #@gui : Cut-off at = float(180,0,180)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- lambert_azimuthal_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=180}
- phi0=0*pi/180
- cutoff={$6*pi/180}
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # There is a bug in the naive formulas I put into this
- # script. Changing phi0 causes the map to get a literal
- # rip hole into it. If that was the only way for me to
- # change the angle of the globe view, this script
- # would be basically pretty useless and would only make
- # maps in one orientation. Happily, you can subsitute
- # those calculations with the usual equirectangular
- # rotation command. In this case, the two below are
- # needed to make "parallel" and "longitude" make sense.
- # The equirectangular_projection command applies the
- # rotations in a specific order. If you try to use it
- # *like* longitudes and parallels, you have to find the
- # equivalent values somehow. Below, to easily get the
- # "right" orientation, first East-West movement is
- # applied, then North-South.
- if $4!=0
- rotate_equirectangular_map 0,0,$4
- endif
- if $5!=0
- rotate_equirectangular_map 0,{-$5},0
- endif
- # width of original map
- nw={0,w}
- # height of original map
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- phi0="$phi0";
- cutoff="$cutoff";
- pi2=2*pi;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2;
- cy=y-h/2;
- # Turn them into radians??
- cx = (cx/w *pi2);
- cy = (cy/w *pi2);
- # For convenience sake. Rho is obviously, in retrospect
- # distance (from center)... At rho==sqrt/2 is where the
- # switch in the atan-function should happen.
- # These are from
- # https://mathworld.wolfram.com/LambertAzimuthalEqual-AreaProjection.html
- rho=sqrt(cx^2 + cy^2);
- C=2*asin(1/2*rho);
- # atan2 can be used here! The formula looks complicated, but just
- # take the parts of the fraction and replace the / with , for the function
- nX = atan2( (cx*sin(C)), ( (rho*cos(phi0)*cos(C))-(cy*sin(phi0)*sin(C))) );
- nY = asin( cos(C)*sin(phi0)+(cy*sin(C)*cos(phi0)) / rho);
- # the sin(phi0)'s cancel out with multiplying by zero, should remove...
- # For the logic behind inverting the formula, check out the
- # Cylindrical Equal-Area filter for a rant
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * nY/pi);
- # Calculate the map's rendering radius based on user's cutoff angle
- # This is a simplified Great Circle distance formula
- # where half the formula disappears because sin(0)=0
- deltaS=acos(cos(nY)*cos(nX));
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range AND inside the deltaS cutoff
- if( (nX>=-pi && nX<=pi && nY>=-pi/2 && nY<=pi/2 && abs(deltaS)<=cutoff),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- # return the last value
- result;"
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- -autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## MOLLWEIDE
- #@gmic mollweide_projection : yaw angle, pitch angle, roll angle, central_longitude angle, standard_parallel angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a Mollweide projection map.
- #@gui Mollweide : mollweide_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a Mollweide equal-area pseudocylindrical map.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Standard parallel = float(0,-90,90)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- mollweide_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0}
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # To apply more standard "longitude" and "standard parallel
- # translations, use the same rotate command, except in an order
- # where longitude (yaw) is applied first and latitude (pitch)
- # is applied second, in two different operations.
- if $4!=0
- rotate_equirectangular_map 0,0,$4
- endif
- if $5!=0
- rotate_equirectangular_map 0,{-$5},0
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2;
- cy=y-h/2;
- # Turn them into radians
- cx = (cx/w *pi2);
- cy = (cy/w *pi2);
- # constants for the formulas. R=1 is the Radius of the globe,
- # I've put 1 here just because i couldn't find a convenient
- # fraction of pi, and it doesn't change the shape, just scale.
- # Theta is separated as a constant following the example of
- # the mathworld equations I found:
- # https://mathworld.wolfram.com/MollweideProjection.html
- R=1;
- theta=asin(cy/(sqrt(2)*R));
- nX = (pi*cx) / (2*R*sqrt(2)*cos(theta));
- nY = asin( ((2*theta)+sin(2*theta)) / pi);
- # For the logic why I'm inverting the formula, check out the
- # Cylindrical Equal-Area filter for a rant
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range
- if( (nX>=-pi && nX<=pi && nY>=-pi/2 && nY<=pi/2),
- # then TAKE the value of X,Y FROM the original equirectangular
- # source map and input the value into x,y in the output.
- result=I(#0,X,Y,0,2,0),
- # else output a transparent pixel
- result=[0,0,0,0]
- );
- # return the last value
- result;"
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- -autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## ORTHOGRAPHIC
- #@gmic orthographic_projection : yaw angle, pitch angle, roll angle, central_longitude angle, standard_parallel angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as an orthographic projection map.
- #@gui Orthographic : orthographic_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as an orthographic hemisphere map. This map projection is basically the view you'd get if you looked at earth from an infinite distance.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Standard parallel = float(0,-90,90)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- orthographic_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0}
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # To apply more standard "longitude" and "standard parallel
- # translations, use the same rotate command, except in an order
- # where longitude (yaw) is applied first and latitude (pitch)
- # is applied second, in two different operations.
- if $4!=0
- rotate_equirectangular_map 0,0,$4
- endif
- if $5!=0
- rotate_equirectangular_map 0,{-$5},0
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2;
- cy=y-h/2;
- # Turn them into radians
- cx = (cx/w *pi2);
- cy = (cy/w *pi2);
- # Formulas and constants:
- # https://en.wikipedia.org/wiki/Orthographic_projection_in_cartography
- # R, radius of globe seems to work best with R=pi/2
- R=pi/2;
- rho=sqrt(cx^2 + cy^2);
- C=asin(rho/R);
- phi0=0;
- l0=0;
- # the formulas are simplified a bit because this script uses
- # phi0=0 and l0=0, leading to anything with sin(phi0) to
- # multiply with 0. The standard parallel and central longitude
- # are calculated earlier with actual global rotations.
- # Happily, here we can use atan2.
- nY = asin((cy*sin(C)*cos(phi0))/rho);
- nX = atan2((cx*sin(C)), (rho*cos(C)*cos(phi0)));
- # For the logic why I'm inverting the formula, check out the
- # Cylindrical Equal-Area filter for a rant
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range
- # Why does this break if the condition is set to true manually???
- if( (nX>-pi && nX<pi && nY>-pi/2 && nY<pi/2),
- # then TAKE the value of X,Y FROM the original equirectangular
- # source map and input the value into x,y in the output.
- result=I(#0,X,Y,0,2,0),
- # else output a transparent pixel
- result=[0,0,0,0]
- );
- # return the last value
- result;"
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- -autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## AZIMUTHAL EQUIDISTANT
- #@gmic azimuthal_equidistant_projection : yaw angle, pitch angle, roll angle, central_longitude angle, standard_parallel angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as an azimuthal equidistant map.
- #@gui Azimuthal equidistant : azimuthal_equidistant_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as an azimuthal equidistant map. All points on the map are at proportionally correct distances from the center point, and that all points on the map are at the correct azimuth (direction) from the center point.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Standard parallel = float(0,-90,90)
- #@gui : Cut-off at = float(180,0,180)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- azimuthal_equidistant_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=180}
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- cutoff={$6*pi/180}
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # To apply more standard "longitude" and "standard parallel
- # translations, use the same rotate command, except in an order
- # where longitude (yaw) is applied first and latitude (pitch)
- # is applied second, in two different operations.
- if $4!=0
- rotate_equirectangular_map 0,0,$4
- endif
- if $5!=0
- rotate_equirectangular_map 0,{-$5},0
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- cutoff="$cutoff";
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi2);
- cy = (cy/w *pi2);
- # Formulas and constants:
- # https://en.wikipedia.org/wiki/Orthographic_projection_in_cartography
- # R, radius of globe seems to work best with R=pi/2
- C=sqrt(cx^2 + cy^2);
- phi0=0;
- l0=0;
- # the formulas are simplified a bit because this script uses
- # phi0=0 and l0=0, leading to anything with sin(phi0) to
- # multiply with 0. The standard parallel and central longitude
- # are calculated earlier with actual global rotations.
- # Happily, here we can use atan2.
- nY = asin( (cy*sin(C)) / C );
- nX = atan2((cx*sin(C)), (C*cos(C)));
- # For the logic why I'm inverting the formula, check out the
- # Cylindrical Equal-Area filter for a rant
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * nY/pi);
- # Calculate the map's rendering radius based on user's cutoff angle
- # This is a simplified Great Circle distance formula
- # where half the formula disappears because sin(0)=0
- deltaS=acos(cos(nY)*cos(nX));
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range AND inside the deltaS cutoff
- if( (nX>=-pi && nX<=pi && nY>=-pi/2 && nY<=pi/2 && abs(deltaS)<=cutoff),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- # generate blank image, then fill_color with bg-color
- -input 100%,100%,1,4,0
- -fill_color[-1] 0,0,0,0
- -shape_circle {-1,w}
- -normalize[-1] 0,255
- -negate[-1]
- +blend_fade[-2,-3] [-1]
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- -autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## CONIC EQUIDISTANT
- #@gmic conic_equidistant_projection : yaw angle, pitch angle, roll angle, central_longitude angle, reference_parallel angle, standard_parallel1 angle, standard_parallel2 angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a conic equidistant map.
- #@gui Conic equidistant : conic_equidistant_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a conic equidistant map. Neither equal-area or conformal.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Reference parallel = float(0,-90,90)
- #@gui : Standard parallel #1 = float(20,-90,90)
- #@gui : Standard parallel #2 = float(60,-90,90)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- conic_equidistant_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=20},${7=60}
- cutoff={$6*pi/180}
- l0=$4
- phi0=$5
- phi1=$6
- phi2=$7
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # To apply more standard "longitude" and "standard parallel
- # translations, use the same rotate command, except in an order
- # where longitude (yaw) is applied first and latitude (pitch)
- # is applied second, in two different operations.
- # if $4!=0
- # rotate_equirectangular_map 0,0,$4
- # endif
- #
- # if $5!=0
- # rotate_equirectangular_map 0,{-$5},0
- # endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- phi0="$phi0"*pi/180;
- l0="$l0"*pi/180;
- phi1="$phi1"*pi/180;
- phi2="$phi2"*pi/180;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi2*4/3);
- cy = -(cy/w *pi2*4/3);
- # Formulas and constants:
- # https://mathworld.wolfram.com/ConicEquidistantProjection.html
- if( (phi1==phi2),
- n=sin(phi1),
- n=(cos(phi1)-cos(phi2)) / (phi2-phi1)
- );
- G=cos(phi1)/n + phi1;
- rho0=G-phi0;
- rho=sign(n)*sqrt( cx^2 + (rho0-cy)^2);
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- # page 114, if using ATAN2, the signs must be reversed.
- # I KNEW THERE WAS SOMETHING WRONG WITH THE FORMULA
- # I had to dig deep.
- if( (n>0),
- (theta=atan2(cx, (rho0-cy))),
- (theta=atan2(-cx, (-rho0+cy)))
- );
- nY = G-rho;
- nX = l0 + theta/n;
- # For the logic why I'm inverting the formula, check out the
- # Cylindrical Equal-Area filter for a rant
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * -nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range, here adjusted for l0 and phi0
- # which are kind of superfluous here, they don't do much anything.
- L=nX-l0;
- P=nY-phi0;
- if( (L>=-pi && L<=pi && P>=-pi/2 && P<=pi/2),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## LAMBERT CONFORMAL CONIC
- #@gmic lambert_conformal_conic_projection : yaw angle, pitch angle, roll angle, central_longitude angle, reference_parallel angle, standard_parallel1 angle, standard_parallel2 angle, latcutoff angle, longcutoff angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a Lambert conic conformal map.
- #@gui Lambert Conformal Conic : lambert_conformal_conic_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a Lambert conic conformal map.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Reference parallel = float(0,-90,90)
- #@gui : Standard parallel #1 = float(20,-90,90)
- #@gui : Standard parallel #2 = float(60,-90,90)
- #@gui : Crop latitude to = float(180,0,180)
- #@gui : Crop longitude to = float(360,0,360)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- lambert_conformal_conic_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=20},${7=60},${8=180},${9=360}
- latcutoff={$8*pi/180}
- longcutoff={$9*pi/180}
- l0=$4
- phi0=$5
- phi1=$6
- phi2=$7
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- phi0="$phi0"*pi/180;
- l0="$l0"*pi/180;
- phi1="$phi1"*pi/180;
- phi2="$phi2"*pi/180;
- latcutoff="$latcutoff";
- longcutoff="$longcutoff";
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi2*pi/2);
- cy = -(cy/w *pi2*pi/2);
- # Formulas and constants:
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- if((phi1==phi2),
- n=sin(phi1),
- n= log(cos(phi1)/cos(phi2)) / log(tan((1/4)*pi+(1/2)*phi2)/tan((1/4)*pi+(1/2)*phi1))
- );
- F=(cos(phi1)*tan((1/4)*pi+(1/2)*phi1)^n) / n;
- rho0=F/tan(1/4*pi+1/2*phi0)^n;
- rho=sign(n)*sqrt( cx^2 + (rho0-cy)^2);
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- # page 114, if using ATAN2, the signs must be reversed.
- if( (n>0),
- (theta=atan2(cx, (rho0-cy))),
- (theta=atan2(-cx, (-rho0+cy)))
- );
- # When the reference parallel is in the southern hemisphere,
- # flip the projection and map
- if( (phi0<0),
- (n=-n)
- );
- if( (rho==0),
- (nY = sign(n)*90*pi/180),
- (nY = 2*atan((F/rho)^(1/n))-1/2*pi)
- );
- nX = l0 + theta/n;
- # For the logic why I'm using inverse formulas, check out the
- # Cylindrical Equal-Area filter
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * -nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range, then further crop to the angles
- # given by the crop values.
- L=nX;
- P=nY;
- if( (L>=l0-longcutoff/2 && L<=l0+longcutoff/2 && P>=phi0-latcutoff/2 && P<=phi0+latcutoff/2),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- # If the reference parallel is in the southern hemisphere,
- # we've flipped the projection. Here we need to further rotate
- # the image so it's not upside down.
- if $phi0<0
- rotate[-1] 180
- endif
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## MERCATOR
- #@gmic mercator : yaw angle, pitch angle, roll angle, central_longitude angle, reference_parallel angle, standard_parallel1 angle, standard_parallel2 angle, latcutoff angle, longcutoff angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as a Mercator projection.
- #@gui Mercator projection : mercator
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as a Mercator projection. You can get a Transverse Mercator by rolling the globe by 90")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Crop latitude to = float(85,0,85)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- mercator :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=85}
- latcutoff={$5*pi/180}
- l0=$4
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- l0="$l0"*pi/180;
- latcutoff="$latcutoff";
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi2);
- cy = -( (cy/w *pi2) );
- # Formulas and constants:
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- nY=atan(sinh(cy));
- nX=l0+cx;
- # For the logic why I'm using inverse formulas, check out the
- # Cylindrical Equal-Area filter
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * -nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range, then further crop to the angles
- # given by the crop values.
- L=nX-l0;
- P=nY;
- if( (L>=-pi && L<=pi && P>=-latcutoff && P<=+latcutoff),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- # X%ow, when combined with an l0 longitude shift, allows for
- # rotating around the globe, otherwise it just cuts off at 180.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## ALBERS EQUAL AREA CONIC
- #@gmic alberts_projection : yaw angle, pitch angle, roll angle, central_longitude angle, reference_parallel angle, standard_parallel1 angle, standard_parallel2 angle, latcutoff angle, longcutoff angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as an Albers equal area conic map.
- #@gui Albers Equal Area Conic : albers_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as an Albers equal area conic projection.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : Reference parallel = float(0,-90,90)
- #@gui : Standard parallel #1 = float(20,-90,90)
- #@gui : Standard parallel #2 = float(60,-90,90)
- #@gui : Crop latitude to = float(180,0,180)
- #@gui : Crop longitude to = float(360,0,360)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- albers_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0},${5=0},${6=20},${7=60},${8=180},${9=360}
- latcutoff={$8*pi/180}
- longcutoff={$9*pi/180}
- l0=$4
- phi0=$5
- phi1=$6
- phi2=$7
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- phi0="$phi0"*pi/180;
- l0="$l0"*pi/180;
- phi1="$phi1"*pi/180;
- phi2="$phi2"*pi/180;
- latcutoff="$latcutoff";
- longcutoff="$longcutoff";
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi2*8/7);
- cy = -(cy/w *pi2*8/7);
- # Formulas and constants:
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- if((phi1==phi2),
- n=sin(phi1),
- n= (sin(phi1)+sin(phi2))/2
- );
- C= cos(phi1)^2 + 2*n*sin(phi1);
- rho0=sqrt((C-2*n*sin(phi0))) / n;
- rho=sqrt(cx^2 + (rho0-cy)^2);
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- # page 114, if using ATAN2, the signs must be reversed.
- if( (n>0),
- (theta=atan2(cx, (rho0-cy))),
- (theta=atan2(-cx, (-rho0+cy)))
- );
- # When the reference parallel is in the southern hemisphere,
- # flip the projection and map
- if( (phi0<0),
- (n=-n)
- );
- if( (rho==0),
- (nY = asin( (C-(rho*n)^2) / (2*n)) ),
- (nY = asin( (C-(rho*n)^2) / (2*n)) )
- );
- nX = l0 + theta/n;
- # For the logic why I'm using inverse formulas, check out the
- # Cylindrical Equal-Area filter
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * -nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range, then further crop to the angles
- # given by the crop values.
- L=nX;
- P=nY;
- if( (L>=l0-longcutoff/2 && L<=l0+longcutoff/2 && P>=phi0-latcutoff/2 && P<=phi0+latcutoff/2),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- # If the reference parallel is in the southern hemisphere,
- # we've flipped the projection. Here we need to further rotate
- # the image so it's not upside down.
- if $phi0<0
- rotate[-1] 180
- endif
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## ECKERT IV
- #@gmic eckert_iv_projection : yaw angle, pitch angle, roll angle, central_longitude angle, reference_parallel angle, standard_parallel1 angle, standard_parallel2 angle, latcutoff angle, longcutoff angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as an Eckert IV map.
- #@gui Eckert IV : eckert_iv_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as an Eckert IV projection.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- eckert_iv_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0}
- l0=$4
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- l0="$l0"*pi/180;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi*sqrt(3));
- cy = -(cy/w *pi*sqrt(3));
- # Formulas and constants:
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- theta=asin(cy*sqrt(4+pi) / (2*sqrt(pi)));
- # When the reference parallel is in the southern hemisphere,
- # flip the projection and map
- nY=asin( (theta + sin(theta)*cos(theta) + 2*sin(theta)) / (2+pi/2));
- nX=l0 + sqrt(pi*(4+pi)) * cx/(2*(1+cos(theta)));
- # For the logic why I'm using inverse formulas, check out the
- # Cylindrical Equal-Area filter
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * -nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range, then further crop to the angles
- # given by the crop values.
- L=nX;
- P=nY;
- if( (L>=l0-pi && L<=l0+pi && P>=-pi/2 && P<=pi/2),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- # If the reference parallel is in the southern hemisphere,
- # we've flipped the projection. Here we need to further rotate
- # the image so it's not upside down.
- if $phi0<0
- rotate[-1] 180
- endif
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
- #######################
- ## ECKERT VI
- #@gmic eckert_vi_projection : yaw angle, pitch angle, roll angle, central_longitude angle, reference_parallel angle, standard_parallel1 angle, standard_parallel2 angle, latcutoff angle, longcutoff angle
- #@gmic : Take a map or equirectangular panorama
- #@gmic : and rotate it around z, y and x angles,
- #@gmic : then project it as an Eckert VI map.
- #@gui Eckert VI : eckert_vi_projection
- #@gui : note = note("Rotate an equirectangular map or panorama around three axises in order and output it as an Eckert VI projection.")
- #@gui : Roll = float(0,-360,360)
- #@gui : Pitch = float(0,-360,360)
- #@gui : Yaw = float(0,-360,360)
- #@gui : Central longitude = float(0,-180,180)
- #@gui : note = note("<small>Author: <i>Kristian Järventaus</i>. Latest Update: <i>2020-08-31</i>.</small>")
- eckert_vi_projection :
- # $1-3 Default to 0 degrees
- -skip ${1=0},${2=0},${3=0},${4=0}
- l0=$4
- # Give input alpha-channel to prevent errors with transparency
- to_a[0]
- _fF_zoomaccurate=1
- _fF_zoomfactor=1
- # First rotate the map with the appropriate custom command
- if $1!=0" || "$2!=0" || "$3!=0
- rotate_equirectangular_map $1,$2,$3
- endif
- # width and height of original map
- nw={0,w}
- nh={0,h}
- # Initialize the image using the above precalculated width and height
- # The "" block contains the mathematical 'formula' that determines
- # what each x,y pixel is.
- -input {$nw+1},{$nw+1},1,4,"
- #inside the ""-block it's easier to pre-translate dollar-variables
- pi2=2*pi;
- l0="$l0"*pi/180;
- # Use centered coordinates. 0,0 is in the middle of the
- # projection
- cx=x-w/2+1;
- cy=y-h/2+1;
- # Turn them into radians
- cx = (cx/w *pi*2);
- cy = -(cy/w *pi*2);
- # Formulas and constants:
- # https://epic.awi.de/id/eprint/39585/1/USGS_Bulletin_1532.pdf
- theta=sqrt(2+pi)*cy/2;
- # When the reference parallel is in the southern hemisphere,
- # flip the projection and map
- nY=asin( (theta + sin(theta)) / (1+pi/2));
- nX=l0 + sqrt(2+pi) * cx/(1+cos(theta));
- # For the logic why I'm using inverse formulas, check out the
- # Cylindrical Equal-Area filter
- # EQUIRECTANGULAR COORDINATES
- # Get the width and height of the original equirectangular input
- ow="{0,w}";
- oh="{0,h}";
- # Pretty simply translate radians coordinates straight into
- # equirectangular pixel coordinates.
- X=ow/2 + (ow * nX/pi2);
- Y=oh/2 + (oh * -nY/pi);
- # check whether the pixel's geographical nX, nY coordinates
- # are within the normal range, then further crop to the angles
- # given by the crop values.
- L=nX;
- P=nY;
- if( (L>=l0-pi && L<=l0+pi && P>=-pi/2 && P<=pi/2),
- # TAKE the value of X,Y FROM the original equirectangular source map
- # and input the value into x,y in the output.
- result=I(#0,X%ow,Y,0,2,0),
- # else output transparent pixel
- result=[0,0,0,0]
- );
- result"
- # If the reference parallel is in the southern hemisphere,
- # we've flipped the projection. Here we need to further rotate
- # the image so it's not upside down.
- if $phi0<0
- rotate[-1] 180
- endif
- # New trick: if you can't calculate the width and height of the image
- # in advance, doing it on a "blank" square image can work as well.
- # In the ""-block of the -input above the last pixel assignment
- # checks if the geographical coordinates we're looking for make
- # any sense, that is, no weird values above or below plus-minus 180 or
- # 90 degrees. If the pixel x,y coordinates would result in something
- # nonsensical, output a transparent pixel. This is necessary, because it's
- # not automatic: you get weird blocks of white *and* transparent
- # lines. Then you can use autocrop from g'mic to do some magic and remove
- # the transparent areas.
- autocrop[-1]
- # Keep the last (. = [-1] image index) image generated
- -keep[-1]
Add Comment
Please, Sign In to add comment