<?xml version="1.0" encoding="utf-8" standalone="yes"?>
<?xml-stylesheet href="./_c74_ref.xsl" type="text/xsl"?>

<c74object name="ambipoint" module="ICST Ambisonics">

    <!--METADATA-->
    <metadatalist>
	<metadata name="author">ICST | Zurich University of the Arts</metadata>
	<metadata name="tag">ICST Ambisonics</metadata>
	<metadata name="copyright">
	 © 2003 - 2021 ICST | Zurich University of the Arts
	</metadata>
	<metadata name="version">
	1.0 (Build 02/2021)
	</metadata>
    </metadatalist>

    <!--DIGEST -> subtitle-->	
    <digest>
	Swiss army knife for ambi-formatted points.
    </digest>

    <!--KEYWORDS-->

    <misc name = "Keywords">
	<entry name ="">
	    <description>
		ambipoint, spatialisation, geometry, affine transforms, formatting, polar-cartesian conversion
	    </description>
	</entry>
    </misc>
	
    <!--DESCRIPTION-->

    <description>
		Ambipoint operations: formatting to, converting between, geometrically transforming or constraining ambipoint coordinates. <br/>
		<p>Operations:</p>
		<ul>
			<li><bi>convert</bi> ambipoint coordinates from polar/spherical to cartesian/rectangular and vice versa.</li>
			<li><bi>label</bi> raw coordinate triplets as ambi-formatted point, adding point-ID &amp; group-ID.</li>
			<li><bi>rotate</bi> ambipoint using quaternion rotations, controlled via Euler-angles.</li>
			<li><bi>translate</bi> ambipoint, either in spherical or rectangular dimensions.</li>
			<li><bi>scale</bi> ambipoint, either in spherical or rectangular dimensions.	</li>
			<li><bi>constrain</bi> ambipoint to grids, radius or sphere, in polar/spherical or cartesian/rectangular dimensions.</li>
		</ul>

    </description>

    <!--DISCUSSION-->
    <discussion>
		<p>An ambi-formatted point is the standard way for transmitting point-information between ICST Ambisonics externals. It contains the following elements:</p>
		<ul>
			<li>&#60;symbol&#62; <b>"aed"</b> to define polar/spherical, <b>"xyz"</b> to define cartesian/rectangular coordinates</li>
			<li>&#60;int&#62; point-ID (minimum 1)</li>
			<li>&#60;float&#62; azimuth or x-value</li>
			<li>&#60;float&#62; elevation or y-value</li>
			<li>&#60;float&#62; distance or z-value</li>
			<li>&#60;int&#62; group-ID (optional, minimum 1)</li>
			<li>&#60;float&#62; yaw &#8594; z-axis rotation (optional)</li>
			<li>&#60;float&#62; pitch &#8594; x-axis rotation (optional)</li>
			<li>&#60;float&#62; roll &#8594; y-axis rotation (optional)</li>
		</ul>
		
		<bluebox>
			The <bi>unit</bi> used for defining the coordinates is of abstract length. It may be defined in feet or meters, whenever real-world measurements come into play, such as for example calculating delay-times based on speed of sound in air. Otherwise It may correspond to the radius of the speaker-circle (unit-sphere on the speaker ring) or the radius of the listener's head (unit sphere at ear distance).
		</bluebox>
		<bluebox>
			The <bi>angles</bi> are defined using a navigation norm (compass degrees). Azimuth zero is due front and positive values turn in a clock-wise direction. Elevation zero is on the horizontal plane and positive values rotate up to reach 90&#176; (+PI/2 rad) at the zenith and down to reach -90&#176; (-PI/2 rad) at the nadir. Consequently, the x-axis points to the right (+x is right), the y-axis points to the front (+y is front) and the z-axis points up (+z is up).
		</bluebox>
		<bluebox>
			<p><i>See also:</i><br/>
			Schacher, J. (2018). Algorithmic Spatialisation. In Dean, R. and McLean, A., editors, Oxford Handbook of Algorithmic Music, pages 471–496. Oxford University Press, Oxford, UK.</p>
				<p>Schacher, J. (2007). Gesture Control of Sounds in 3D Space. In Proceedings of the Conference on New Interfaces for Musical Expression NIME’07, New York, NY.</p>
			</bluebox>
    </discussion>

    <!--INLETS-->
    <!--do not use-->
    <inletlist>
    </inletlist>

    <!--OUTLETS-->
    <!--do not use-->
    <outletlist>
    </outletlist>

    <!--ARGUMENTS-->
    <objarglist>
	<objarg name="mode" optional="1" type="symbol">
	    <description>
		The mode of operation. Modes are: convert, label, rotate, translate, scale, constrain.
	    </description>
	</objarg>
    </objarglist>

    <!--MESSAGES-->
    <methodlist>
	<method name="bang">
	    <description>
			Output previous point, if set.
	    </description>
	</method>
	
	<method name="int">
	    <description>
			In mode <bi>label</bi>: input first coordinate dimension (converted to float).
	    </description>
	</method>	

	<method name="float">
	    <description>
			In mode <bi>label</bi> input first coordinate dimension.
	    </description>
	</method>		

	<method name="list">
	    <description>
			Input raw coordinate triplets (or 6DOF sextuplets).
	    </description>
	</method>
	
	<method name="set">
	    <description>
			In mode <bi>label</bi>: set raw coordinate triplets (or 6DOF sextuplets) without triggering any output.<br/><br/>
			In mode <bi>convert</bi>: set ambipoint without triggering any output.
	    </description>
	</method>
	
	<method name="aed">
	    <description>
			In all modes except <bi>label</bi>: Input ambipoint with cartesian/rectangular coordinates (incl. group-ID &amp; orientation).<br/><br/>
			Format of polar/spherical ambipoint:<br/> 
			<code>"aed" &#60;point-ID&#62; &#60;azimuth&#62; &#60;elevation&#62; &#60;distance&#62; &#60;group-ID&#62; &#60;yaw&#62; &#60;pitch&#62; &#60;roll&#62;</code>
	    </description>
	</method>
	
	<method name="xyz">
	    <description>
			All modes except <bi>label</bi>: Input ambipoint with polar/spherical coordinates (incl. group-ID &amp; orientation).<br/><br/>
			Format of cartesian/rectangular ambipoint:<br/> 
			<code>"xyz" &#60;point-ID&#62; &#60;x-value&#62; &#60;y-value&#62; &#60;z-value&#62; &#60;group-ID&#62;  &#60;yaw&#62; &#60;pitch&#62; &#60;roll&#62;</code>
		</description>
	</method>
	
	<method name="version">
	    <description>
			Print version information to Max' console window.
	    </description>
	</method>
    </methodlist>

    <!--ATTRIBUTES-->
    <attributelist>
	<attribute name="mode" get="0" set="0" type="symbol" size="1" value="Mode">
	    <description>
			Modes: convert, label, rotate, translate, scale, constrain.
		</description>
	</attribute>
	
	<attribute name="ID" get="0" set="0" type="int" size="1" value="Point ID">
	    <description>
			In mode <bi>label</bi>: Set the point ID for a coordinate triplet (minimum value is 1).
	    </description>
	</attribute>
	
	<attribute name="group" get="0" set="0" type="int" size="1" value="Group ID">
	    <description>
			In mode <bi>label</bi>: Set the group ID for a coordinate triplet (minimum value is 1).
	    </description>
	</attribute>

	<attribute name="coord_angles" get="0" set="0" type="int" size="1" value="Angle Type">
	    <description>
			In mode  <bi>rotate</bi>: input-angle type: 
			<ul>
				<li>0: Degrees - input angles in degrees (default).</li>
				<li>1: Radians - input angles in radians.</li>
			</ul>
	    </description>
	</attribute>
	
	<attribute name="coord_system" get="0" set="0" type="int" size="1" value="Coordinate System">
	    <description>
			In mode <bi>label</bi>, <bi>rotate</bi>, <bi>translate</bi>, <bi>scale</bi> and all raw coordinate operations: input coordinate system type
			<ul>
				<li>0: Polar - operate in polar coordinates - aka. spherical.</li>
				<li>1: Cartesian - operate in cartesian coordinates - aka. rectangular (default).</li>
			</ul>
	    </description>
	</attribute>
	
	<attribute name="rotate_order" get="0" set="0" type="int" size="1" value="Scene rotate order">
	    <description>
			In mode <bi>rotate</bi>: determines the order of rotations.<br/>
			Options are: xyz, xzy, yxz, yzx, zxy, zyx; and: xyx, xzx, yxy, yzy, zxz, zyz. <br/>
			The order of rotations and not permutable, i.e, changing he order of rotation changes the outcome.
			The first six options rotate about all three axes, the following six rotate about two axes only.
			<bluebox><p><b>NB:</b> The option <bi>zyx</bi> (default) is the most commonly used and produces the generally expected order of yaw-pitch-roll.</p>
			<p><i>"The order of rotations follows the M*v convention, meaning that XYZ returns the Euler angles for rotating a vector v in the order X * (Y * (Z * v))). If you don't know which one to use, then it's probably the Euler ZYX."</i></p>
			<p><i>See also:</i><br/>
			Henderson, D. M. (1977), Euler Angles, Quaternions, and Transformation Matrices - Working Relationships, (NASA-TM-74839), download <a href='https://ntrs.nasa.gov/api/citations/19770024290/downloads/19770024290.pdf'>pdf</a> (last accessed 2020/12/13).</p>
		</bluebox>
	    </description>
	</attribute>
	
	<attribute name="rotation" get="0" set="0" type="float" size="3" value="Scene rotation">
	    <description>
		In mode <bi>rotate</bi>: set the three rotation values. <br/><br/>
		Does not trigger ambipoint operation itself. When done setting, notifies from third outlet with [rotate ready] message - this can be used to input the points to be operated on.
	    </description>
	</attribute>
	
	<attribute name="translation" get="0" set="0" type="float" size="3" value="Scene translation">
	    <description>
		In mode <bi>translate</bi>: set the three translation values. <br/><br/>
		Depending on the selected coordinate system (attribute coord_system), the operation will be carried out in spherical or rectangular units.<br/><br/>
		Does not trigger ambipoint operation itself. When done setting, notifies from third outlet with [translate ready] message - this can be used to input the points to be operated on.
	    </description>
	</attribute>
	
	<attribute name="scaling" get="0" set="0" type="float" size="3" value="Scene scaling">
	    <description>
		In mode <bi>scale</bi>: set the three scaling values. <br/><br/>
		Depending on the selected coordinate system (attribute coord_system), the operation will be carried out in spherical or rectangular units.<br/><br/>
		Does not trigger ambipoint operation itself. When done setting, notifies from third outlet with [scale ready] message - this can be used to input the points to be operated on.
	    </description>
	</attribute>
	
	<attribute name="constrain" get="0" set="0" type="int" size="1" value="Constrain Method">
	    <description>
		In mode <bi>constrain</bi>: set the constraining algorithm:<br/>
		<ul>
			<li>off: no constraint</li>
			<li>grid-xyz: snap point to <bi>xyz</bi> grid (grid_unit_xyz)</li>
			<li>grid-aed: snap point to <bi>aed</bi> grid (grid_unit_ae &amp; grid_unit_d)</li>
			<li>grid-d: snap point to distance grid only (grid_unit_d)</li>
			<li>snap to radius 2D: force to circle with 'constrain radius', discarding elevation.</li>
			<li>snap to sphere 3D: force to sphere with 'constrain radius'</li>
			<li>skirt radius 2D: inside radius forces to circle with 'constrain radius', outside remains unaffected</li>
			<li>skirt sphere 3D: inside radius forces to sphere with 'constrain radius', outside remains unaffected</li>
		</ul>
	    </description>
	</attribute>
	
	<attribute name="constrain_radius" get="0" set="0" type="float" size="1" value="Constrain Radius">
	    <description>
			In mode <bi>constrain</bi>: set the radius for the 'snap' and 'skirt' operations, <m>both 2D and 3D</m>.
	    </description>
	</attribute>
	
	<attribute name="grid_unit_xyz" get="0" set="0" type="float" size="1" value="Grid Unit xyz">
	    <description> 
			In mode <bi>constrain</bi>: set the step for the rectangular grid in units. Forced to integer fraction of 1 (minimum: 0.01, maximum: 1.0, default: 0.1). Example:
			<code>
			fraction = 1.0 / grid_unit_xyz;
			grid_unit_xyz = 1.0 / round(fraction);
		</code>
	    </description>
	</attribute>
	
	<attribute name="grid_unit_ae" get="0" set="0" type="float" size="1" value="Grid Unit ae">
	    <description>
			In mode <bi>constrain</bi>: set the step for the spherical grid's azimuth and elevation in even subdivisions of 180 degrees (minimum: 0, maximum: 72, default: 8). Example: <code>grid_unit_ae = 8;<br/> 180.0 / grid_unit_ae = 22.5; // degrees per grid-step.</code>
	    </description>
	</attribute>	
	
	<attribute name="grid_unit_d" get="0" set="0" type="float" size="1" value="Grid Unit d">
	    <description>
			In mode <bi>constrain</bi>: Set the step for the spherical grid's distance in units. Forced to integer fraction of 1 (minimum: 0.01, maximum: 1.0, default: 0.1). Example: 
			<code>
			fraction = 1.0 / grid_unit_xyz;
			grid_unit_xyz = 1.0 / round(fraction);
		</code>
	    </description>
	</attribute>	
    </attributelist>
	
	
    <misc name = "Input">
	<entry name ="Inlet 1 [bang, int, float, list, anything]">
	    <description>
		Input raw coordinate lists, fully formatted ambipoints, transform parameters and other messages.
	    </description>
	</entry>
    </misc>

    <!--INLETS / OUTLETS-->
    <misc name = "Output">
	<entry name ="Outlet 1 [list]">
	    <description>
		Outputs ambipoint with polar/spherical coordinate (aed ...) or raw coordinate triplet (in transform modes with raw input).
	    </description>
	</entry>
	<entry name ="Outlet 2 [list]">
	    <description>
			Outputs ambipoint with cartesian/rectangular coordinate (xyz ...)
	    </description>
	</entry>
	<entry name ="Outlet 3 [list]">
	    <description>
			Outputs notifications for rotate, translate, and scale operations.
	    </description>
	</entry>
    </misc>


	
    <!--SEEALSO-->
	<seealsolist>

		<seealso name="ambimonitor"/>
		<seealso name="ambicontrol"/>
		<!-- <seealso name="ambipoint"/> -->
		
		<seealso name="icst.map"/>
		<seealso name="icst.random"/>
		<seealso name="icst.spline"/>
		
		<seealso name="icst.button"/>
		<seealso name="icst.intui"/>
		<seealso name="icst.floatui"/>
		<seealso name="icst.listui"/>

		<seealso name="ambiencode~"/>
		<seealso name="ambidecode~"/>
		<seealso name="ambipanning~"/>
				
		<seealso name="mc.ambiencode~"/>
		<seealso name="mc.ambidecode~"/>
		<seealso name="mc.ambipanning~"/>
		
	</seealsolist>

</c74object>
