head	8.7;
access;
symbols;
locks; strict;
comment	@ * @;


8.7
date	2026.05.11.12.01.10;	author mcalabre;	state Exp;
branches;
next	8.6;

8.6
date	2026.03.29.13.53.56;	author mcalabre;	state Exp;
branches
	8.6.1.1;
next	8.5;

8.5
date	2025.12.06.13.47.41;	author mcalabre;	state Exp;
branches
	8.5.1.1;
next	8.4;

8.4
date	2024.10.28.13.56.16;	author mcalabre;	state Exp;
branches
	8.4.1.1;
next	8.3;

8.3
date	2024.05.13.16.33.00;	author mcalabre;	state Exp;
branches
	8.3.1.1;
next	8.2;

8.2
date	2023.11.16.10.00.29;	author mcalabre;	state Exp;
branches
	8.2.1.1;
next	8.1;

8.1
date	2023.07.05.17.12.07;	author mcalabre;	state Exp;
branches
	8.1.1.1;
next	8.0;

8.0
date	2023.07.01.06.15.04;	author mcalabre;	state Exp;
branches
	8.0.1.1;
next	7.13;

7.13
date	2022.10.07.03.43.35;	author mcalabre;	state Exp;
branches
	7.13.1.1;
next	7.12;

7.12
date	2022.09.09.04.57.58;	author mcalabre;	state Exp;
branches
	7.12.1.1;
next	7.11;

7.11
date	2022.04.26.06.13.52;	author mcalabre;	state Exp;
branches
	7.11.1.1;
next	7.10;

7.10
date	2022.04.23.14.25.15;	author mcalabre;	state Exp;
branches
	7.10.1.1;
next	7.9;

7.9
date	2022.03.25.15.14.48;	author mcalabre;	state Exp;
branches
	7.9.1.1;
next	7.8;

7.8
date	2022.03.25.06.11.49;	author mcalabre;	state Exp;
branches
	7.8.1.1;
next	7.7;

7.7
date	2021.07.12.06.36.49;	author mcalabre;	state Exp;
branches
	7.7.1.1;
next	7.6;

7.6
date	2021.04.13.12.57.01;	author mcalabre;	state Exp;
branches
	7.6.1.1;
next	7.5;

7.5
date	2021.03.20.05.54.58;	author mcalabre;	state Exp;
branches
	7.5.1.1;
next	7.4;

7.4
date	2021.01.31.02.24.51;	author mcalabre;	state Exp;
branches
	7.4.1.1;
next	7.3;

7.3
date	2020.06.03.03.37.02;	author mcalabre;	state Exp;
branches
	7.3.1.1;
next	7.2;

7.2
date	2020.03.09.07.31.23;	author mcalabre;	state Exp;
branches
	7.2.1.1;
next	7.1;

7.1
date	2019.12.31.13.25.19;	author mcalabre;	state Exp;
branches
	7.1.1.1;
next	6.4;

6.4
date	2019.08.15.09.30.18;	author mcalabre;	state Exp;
branches
	6.4.1.1;
next	6.3;

6.3
date	2019.07.12.07.33.39;	author mcalabre;	state Exp;
branches
	6.3.1.1;
next	6.2;

6.2
date	2018.10.20.10.03.13;	author mcalabre;	state Exp;
branches
	6.2.1.1;
next	6.1;

6.1
date	2018.10.19.08.35.17;	author mcalabre;	state Exp;
branches
	6.1.1.1;
next	5.20;

5.20
date	2018.10.05.05.32.41;	author mcalabre;	state Exp;
branches
	5.20.1.1;
next	5.19;

5.19
date	2018.07.26.15.37.04;	author mcalabre;	state Exp;
branches
	5.19.1.1;
next	5.18;

5.18
date	2018.01.10.08.32.14;	author mcalabre;	state Exp;
branches
	5.18.1.1;
next	5.17;

5.17
date	2017.09.18.08.44.23;	author mcalabre;	state Exp;
branches
	5.17.1.1;
next	5.16;

5.16
date	2017.01.15.04.25.01;	author mcalabre;	state Exp;
branches
	5.16.1.1;
next	5.15;

5.15
date	2016.04.05.12.55.10;	author mcalabre;	state Exp;
branches
	5.15.1.1;
next	5.14;

5.14
date	2016.02.07.10.49.31;	author mcalabre;	state Exp;
branches
	5.14.1.1;
next	5.13;

5.13
date	2016.01.26.08.51.13;	author mcalabre;	state Exp;
branches
	5.13.1.1;
next	5.12;

5.12
date	2015.11.15.02.13.00;	author mcalabre;	state Exp;
branches
	5.12.1.1;
next	5.11;

5.11
date	2015.10.18.09.13.05;	author mcalabre;	state Exp;
branches
	5.11.1.1;
next	5.10;

5.10
date	2015.10.09.08.19.15;	author mcalabre;	state Exp;
branches
	5.10.1.1;
next	5.9;

5.9
date	2015.07.21.09.20.01;	author mcalabre;	state Exp;
branches
	5.9.1.1;
next	5.8;

5.8
date	2015.07.08.11.03.59;	author mcalabre;	state Exp;
branches
	5.8.1.1;
next	5.7;

5.7
date	2015.06.29.02.44.16;	author mcalabre;	state Exp;
branches
	5.7.1.1;
next	5.6;

5.6
date	2015.06.14.07.11.24;	author mcalabre;	state Exp;
branches
	5.6.1.1;
next	5.5;

5.5
date	2015.05.05.13.16.31;	author mcalabre;	state Exp;
branches
	5.5.1.1;
next	5.4;

5.4
date	2015.04.21.14.41.05;	author mcalabre;	state Exp;
branches
	5.4.1.1;
next	5.3;

5.3
date	2015.04.21.02.50.51;	author mcalabre;	state Exp;
branches
	5.3.1.1;
next	5.2;

5.2
date	2015.04.15.12.35.07;	author mcalabre;	state Exp;
branches
	5.2.1.1;
next	5.1;

5.1
date	2015.04.07.10.56.36;	author mcalabre;	state Exp;
branches
	5.1.1.1;
next	5.0;

5.0
date	2015.04.05.12.24.59;	author mcalabre;	state Exp;
branches
	5.0.1.1;
next	4.25;

4.25
date	2014.12.14.14.29.36;	author mcalabre;	state Exp;
branches
	4.25.1.1;
next	4.24;

4.24
date	2014.09.18.15.25.00;	author mcalabre;	state Exp;
branches
	4.24.1.1;
next	4.23;

4.23
date	2014.05.13.05.50.51;	author mcalabre;	state Exp;
branches
	4.23.1.1;
next	4.22;

4.22
date	2014.04.12.15.03.52;	author mcalabre;	state Exp;
branches
	4.22.1.1;
next	4.21;

4.21
date	2014.03.24.05.12.27;	author mcalabre;	state Exp;
branches
	4.21.1.1;
next	4.20;

4.20
date	2013.12.18.05.42.49;	author mcalabre;	state Exp;
branches
	4.20.1.1;
next	4.19;

4.19
date	2013.09.29.14.17.51;	author mcalabre;	state Exp;
branches
	4.19.1.1;
next	4.18;

4.18
date	2013.07.13.10.00.04;	author mcalabre;	state Exp;
branches
	4.18.1.1;
next	4.17;

4.17
date	2013.01.29.05.29.20;	author cal103;	state Exp;
branches
	4.17.1.1;
next	4.16;

4.16
date	2012.11.07.04.42.44;	author cal103;	state Exp;
branches
	4.16.1.1;
next	4.15;

4.15
date	2012.09.26.14.26.05;	author cal103;	state Exp;
branches
	4.15.1.1;
next	4.14;

4.14
date	2012.07.13.10.02.27;	author cal103;	state Exp;
branches
	4.14.1.1;
next	4.13;

4.13
date	2012.03.14.07.39.30;	author cal103;	state Exp;
branches
	4.13.1.1;
next	4.12;

4.12
date	2012.02.29.07.57.56;	author cal103;	state Exp;
branches
	4.12.1.1;
next	4.11;

4.11
date	2012.02.20.23.30.02;	author cal103;	state Exp;
branches
	4.11.1.1;
next	4.10;

4.10
date	2012.02.05.23.41.44;	author cal103;	state Exp;
branches
	4.10.1.1;
next	4.9;

4.9
date	2012.01.24.05.40.29;	author cal103;	state Exp;
branches
	4.9.1.1;
next	4.8;

4.8
date	2011.08.15.08.05.53;	author cal103;	state Exp;
branches
	4.8.1.1;
next	4.7;

4.7
date	2011.02.07.07.03.42;	author cal103;	state Exp;
branches
	4.7.1.1;
next	4.6;

4.6
date	2010.11.16.06.15.31;	author cal103;	state Exp;
branches
	4.6.1.1;
next	4.5;

4.5
date	2010.07.16.07.01.25;	author cal103;	state Exp;
branches
	4.5.1.1;
next	4.4;

4.4
date	2009.08.06.07.41.33;	author cal103;	state Exp;
branches
	4.4.1.1;
next	4.3;

4.3
date	2007.12.27.05.41.36;	author cal103;	state Exp;
branches
	4.3.1.1;
next	4.2;

4.2
date	2005.09.22.08.59.02;	author cal103;	state Exp;
branches
	4.2.1.1;
next	4.1;

4.1
date	2005.08.31.03.52.31;	author cal103;	state Exp;
branches;
next	4.0;

4.0
date	2005.02.06.11.47.16;	author cal103;	state Exp;
branches;
next	0.0;

0.0
date	2005.02.04.12.59.26;	author cal103;	state Exp;
branches;
next	;

4.2.1.1
date	2005.12.05.02.39.43;	author cal103;	state Exp;
branches;
next	4.2.1.2;

4.2.1.2
date	2006.06.01.07.34.15;	author cal103;	state Exp;
branches;
next	4.2.1.3;

4.2.1.3
date	2006.06.01.07.47.53;	author cal103;	state Exp;
branches;
next	4.2.1.4;

4.2.1.4
date	2007.06.29.00.43.47;	author cal103;	state Exp;
branches;
next	4.2.1.5;

4.2.1.5
date	2007.07.11.02.01.30;	author cal103;	state Exp;
branches;
next	4.2.1.6;

4.2.1.6
date	2007.12.03.05.02.17;	author cal103;	state Exp;
branches;
next	;

4.3.1.1
date	2007.12.27.13.23.47;	author cal103;	state Exp;
branches;
next	4.3.1.2;

4.3.1.2
date	2009.07.22.04.28.39;	author cal103;	state Exp;
branches;
next	;

4.4.1.1
date	2009.08.10.08.52.49;	author cal103;	state Exp;
branches;
next	4.4.1.2;

4.4.1.2
date	2010.01.19.03.42.50;	author cal103;	state Exp;
branches;
next	;

4.5.1.1
date	2010.07.16.07.05.31;	author cal103;	state Exp;
branches;
next	;

4.6.1.1
date	2010.11.16.06.16.19;	author cal103;	state Exp;
branches;
next	4.6.1.2;

4.6.1.2
date	2011.01.14.06.33.16;	author cal103;	state Exp;
branches;
next	4.6.1.3;

4.6.1.3
date	2011.01.25.00.35.11;	author cal103;	state Exp;
branches;
next	4.6.1.4;

4.6.1.4
date	2011.02.01.05.38.50;	author cal103;	state Exp;
branches;
next	4.6.1.5;

4.6.1.5
date	2011.02.03.05.21.04;	author cal103;	state Exp;
branches;
next	4.6.1.6;

4.6.1.6
date	2011.02.03.05.32.17;	author cal103;	state Exp;
branches;
next	4.6.1.7;

4.6.1.7
date	2011.02.04.06.29.24;	author cal103;	state Exp;
branches;
next	4.6.1.8;

4.6.1.8
date	2011.02.07.04.28.45;	author cal103;	state Exp;
branches;
next	;

4.7.1.1
date	2011.02.07.07.04.22;	author cal103;	state Exp;
branches;
next	4.7.1.2;

4.7.1.2
date	2011.07.21.03.43.08;	author cal103;	state Exp;
branches;
next	4.7.1.3;

4.7.1.3
date	2011.08.09.02.43.50;	author cal103;	state Exp;
branches;
next	4.7.1.4;

4.7.1.4
date	2011.08.10.04.49.56;	author cal103;	state Exp;
branches;
next	4.7.1.5;

4.7.1.5
date	2011.08.12.05.42.29;	author cal103;	state Exp;
branches;
next	;

4.8.1.1
date	2011.08.15.08.07.06;	author cal103;	state Exp;
branches;
next	4.8.1.2;

4.8.1.2
date	2011.11.17.03.09.49;	author cal103;	state Exp;
branches;
next	4.8.1.3;

4.8.1.3
date	2012.01.24.05.23.06;	author cal103;	state Exp;
branches;
next	;

4.9.1.1
date	2012.01.24.05.41.45;	author cal103;	state Exp;
branches;
next	;

4.10.1.1
date	2012.02.05.23.42.46;	author cal103;	state Exp;
branches;
next	;

4.11.1.1
date	2012.02.20.23.31.13;	author cal103;	state Exp;
branches;
next	;

4.12.1.1
date	2012.02.29.07.59.10;	author cal103;	state Exp;
branches;
next	4.12.1.2;

4.12.1.2
date	2012.03.14.06.39.48;	author cal103;	state Exp;
branches;
next	;

4.13.1.1
date	2012.03.14.07.40.37;	author cal103;	state Exp;
branches;
next	4.13.1.2;

4.13.1.2
date	2012.07.12.15.34.49;	author cal103;	state Exp;
branches;
next	4.13.1.3;

4.13.1.3
date	2012.07.13.03.34.20;	author cal103;	state Exp;
branches;
next	;

4.14.1.1
date	2012.07.13.10.04.44;	author cal103;	state Exp;
branches;
next	;

4.15.1.1
date	2012.09.26.14.27.51;	author cal103;	state Exp;
branches;
next	;

4.16.1.1
date	2012.11.07.04.45.56;	author cal103;	state Exp;
branches;
next	4.16.1.2;

4.16.1.2
date	2013.01.29.05.09.44;	author cal103;	state Exp;
branches;
next	;

4.17.1.1
date	2013.01.29.05.32.32;	author cal103;	state Exp;
branches;
next	;

4.18.1.1
date	2013.07.13.10.02.37;	author mcalabre;	state Exp;
branches;
next	;

4.19.1.1
date	2013.09.29.14.20.38;	author mcalabre;	state Exp;
branches;
next	;

4.20.1.1
date	2013.12.18.05.46.55;	author mcalabre;	state Exp;
branches;
next	4.20.1.2;

4.20.1.2
date	2014.03.21.06.32.19;	author mcalabre;	state Exp;
branches;
next	;

4.21.1.1
date	2014.03.24.05.15.28;	author mcalabre;	state Exp;
branches;
next	;

4.22.1.1
date	2014.04.12.15.06.32;	author mcalabre;	state Exp;
branches;
next	4.22.1.2;

4.22.1.2
date	2014.05.10.14.31.52;	author mcalabre;	state Exp;
branches;
next	4.22.1.3;

4.22.1.3
date	2014.05.11.04.06.31;	author mcalabre;	state Exp;
branches;
next	;

4.23.1.1
date	2014.05.13.05.53.49;	author mcalabre;	state Exp;
branches;
next	4.23.1.2;

4.23.1.2
date	2014.05.22.10.51.36;	author mcalabre;	state Exp;
branches;
next	;

4.24.1.1
date	2014.09.18.15.28.09;	author mcalabre;	state Exp;
branches;
next	;

4.25.1.1
date	2014.12.14.14.32.45;	author mcalabre;	state Exp;
branches;
next	4.25.1.2;

4.25.1.2
date	2015.01.06.01.01.06;	author mcalabre;	state Exp;
branches;
next	4.25.1.3;

4.25.1.3
date	2015.03.05.14.37.20;	author mcalabre;	state Exp;
branches;
next	4.25.1.4;

4.25.1.4
date	2015.04.03.01.34.23;	author mcalabre;	state Exp;
branches;
next	;

5.0.1.1
date	2015.04.05.12.28.00;	author mcalabre;	state Exp;
branches;
next	;

5.1.1.1
date	2015.04.07.11.01.10;	author mcalabre;	state Exp;
branches;
next	;

5.2.1.1
date	2015.04.15.12.39.14;	author mcalabre;	state Exp;
branches;
next	;

5.3.1.1
date	2015.04.21.02.54.02;	author mcalabre;	state Exp;
branches;
next	;

5.4.1.1
date	2015.04.21.14.44.28;	author mcalabre;	state Exp;
branches;
next	;

5.5.1.1
date	2015.05.05.13.21.00;	author mcalabre;	state Exp;
branches;
next	;

5.6.1.1
date	2015.06.14.07.14.44;	author mcalabre;	state Exp;
branches;
next	5.6.1.2;

5.6.1.2
date	2015.06.18.08.13.35;	author mcalabre;	state Exp;
branches;
next	;

5.7.1.1
date	2015.06.29.02.47.24;	author mcalabre;	state Exp;
branches;
next	;

5.8.1.1
date	2015.07.08.11.07.18;	author mcalabre;	state Exp;
branches;
next	;

5.9.1.1
date	2015.07.21.09.28.07;	author mcalabre;	state Exp;
branches;
next	;

5.10.1.1
date	2015.10.09.08.22.35;	author mcalabre;	state Exp;
branches;
next	;

5.11.1.1
date	2015.10.18.09.16.27;	author mcalabre;	state Exp;
branches;
next	;

5.12.1.1
date	2015.11.15.02.16.14;	author mcalabre;	state Exp;
branches;
next	5.12.1.2;

5.12.1.2
date	2016.01.25.05.17.04;	author mcalabre;	state Exp;
branches;
next	;

5.13.1.1
date	2016.01.26.08.54.32;	author mcalabre;	state Exp;
branches;
next	;

5.14.1.1
date	2016.02.07.10.52.44;	author mcalabre;	state Exp;
branches;
next	;

5.15.1.1
date	2016.04.05.12.58.35;	author mcalabre;	state Exp;
branches;
next	5.15.1.2;

5.15.1.2
date	2017.01.15.04.13.33;	author mcalabre;	state Exp;
branches;
next	;

5.16.1.1
date	2017.01.15.04.28.59;	author mcalabre;	state Exp;
branches;
next	5.16.1.2;

5.16.1.2
date	2017.09.12.13.07.57;	author mcalabre;	state Exp;
branches;
next	5.16.1.3;

5.16.1.3
date	2017.09.12.14.21.25;	author mcalabre;	state Exp;
branches;
next	;

5.17.1.1
date	2017.09.18.08.45.59;	author mcalabre;	state Exp;
branches;
next	5.17.1.2;

5.17.1.2
date	2018.01.10.08.25.34;	author mcalabre;	state Exp;
branches;
next	;

5.18.1.1
date	2018.01.10.08.33.04;	author mcalabre;	state Exp;
branches;
next	5.18.1.2;

5.18.1.2
date	2018.07.25.01.10.31;	author mcalabre;	state Exp;
branches;
next	;

5.19.1.1
date	2018.07.26.15.41.40;	author mcalabre;	state Exp;
branches;
next	;

5.20.1.1
date	2018.10.05.05.33.33;	author mcalabre;	state Exp;
branches;
next	;

6.1.1.1
date	2018.10.19.08.36.15;	author mcalabre;	state Exp;
branches;
next	;

6.2.1.1
date	2018.10.20.10.04.15;	author mcalabre;	state Exp;
branches;
next	6.2.1.2;

6.2.1.2
date	2019.05.10.01.56.50;	author mcalabre;	state Exp;
branches;
next	6.2.1.3;

6.2.1.3
date	2019.07.08.03.33.03;	author mcalabre;	state Exp;
branches;
next	6.2.1.4;

6.2.1.4
date	2019.07.08.05.09.44;	author mcalabre;	state Exp;
branches;
next	6.2.1.5;

6.2.1.5
date	2019.07.09.08.49.45;	author mcalabre;	state Exp;
branches;
next	;

6.3.1.1
date	2019.07.12.07.34.37;	author mcalabre;	state Exp;
branches;
next	;

6.4.1.1
date	2019.08.15.09.31.29;	author mcalabre;	state Exp;
branches;
next	6.4.1.2;

6.4.1.2
date	2019.11.29.04.16.06;	author mcalabre;	state Exp;
branches;
next	6.4.1.3;

6.4.1.3
date	2019.12.31.02.16.57;	author mcalabre;	state Exp;
branches;
next	6.4.1.4;

6.4.1.4
date	2019.12.31.03.28.03;	author mcalabre;	state Exp;
branches;
next	6.4.1.5;

6.4.1.5
date	2019.12.31.13.06.14;	author mcalabre;	state Exp;
branches;
next	;

7.1.1.1
date	2019.12.31.13.28.19;	author mcalabre;	state Exp;
branches;
next	;

7.2.1.1
date	2020.03.09.07.34.50;	author mcalabre;	state Exp;
branches;
next	;

7.3.1.1
date	2020.06.03.03.38.10;	author mcalabre;	state Exp;
branches;
next	7.3.1.2;

7.3.1.2
date	2020.08.17.11.19.09;	author mcalabre;	state Exp;
branches;
next	7.3.1.3;

7.3.1.3
date	2021.01.19.14.09.10;	author mcalabre;	state Exp;
branches;
next	7.3.1.4;

7.3.1.4
date	2021.01.28.12.29.30;	author mcalabre;	state Exp;
branches;
next	;

7.4.1.1
date	2021.01.31.02.26.24;	author mcalabre;	state Exp;
branches;
next	;

7.5.1.1
date	2021.03.20.05.56.42;	author mcalabre;	state Exp;
branches;
next	7.5.1.2;

7.5.1.2
date	2021.04.06.15.49.44;	author mcalabre;	state Exp;
branches;
next	7.5.1.3;

7.5.1.3
date	2021.04.07.04.49.53;	author mcalabre;	state Exp;
branches;
next	7.5.1.4;

7.5.1.4
date	2021.04.13.09.22.52;	author mcalabre;	state Exp;
branches;
next	;

7.6.1.1
date	2021.04.13.13.00.35;	author mcalabre;	state Exp;
branches;
next	;

7.7.1.1
date	2021.07.12.06.38.27;	author mcalabre;	state Exp;
branches;
next	7.7.1.2;

7.7.1.2
date	2022.03.25.06.05.59;	author mcalabre;	state Exp;
branches;
next	;

7.8.1.1
date	2022.03.25.06.14.14;	author mcalabre;	state Exp;
branches;
next	;

7.9.1.1
date	2022.03.25.15.16.40;	author mcalabre;	state Exp;
branches;
next	7.9.1.2;

7.9.1.2
date	2022.04.03.06.17.15;	author mcalabre;	state Exp;
branches;
next	;

7.10.1.1
date	2022.04.23.14.26.54;	author mcalabre;	state Exp;
branches;
next	7.10.1.2;

7.10.1.2
date	2022.04.26.05.42.08;	author mcalabre;	state Exp;
branches;
next	;

7.11.1.1
date	2022.04.26.06.15.32;	author mcalabre;	state Exp;
branches;
next	;

7.12.1.1
date	2022.09.09.05.00.36;	author mcalabre;	state Exp;
branches;
next	;

7.13.1.1
date	2022.10.07.03.45.47;	author mcalabre;	state Exp;
branches;
next	7.13.1.2;

7.13.1.2
date	2023.06.15.04.17.19;	author mcalabre;	state Exp;
branches;
next	;

8.0.1.1
date	2023.07.01.06.22.44;	author mcalabre;	state Exp;
branches;
next	;

8.1.1.1
date	2023.07.05.17.15.00;	author mcalabre;	state Exp;
branches;
next	;

8.2.1.1
date	2023.11.16.10.05.57;	author mcalabre;	state Exp;
branches;
next	8.2.1.2;

8.2.1.2
date	2023.11.29.07.39.44;	author mcalabre;	state Exp;
branches;
next	8.2.1.3;

8.2.1.3
date	2024.04.02.14.01.58;	author mcalabre;	state Exp;
branches;
next	8.2.1.4;

8.2.1.4
date	2024.05.08.08.58.26;	author mcalabre;	state Exp;
branches;
next	8.2.1.5;

8.2.1.5
date	2024.05.08.15.15.50;	author mcalabre;	state Exp;
branches;
next	8.2.1.6;

8.2.1.6
date	2024.05.08.15.39.34;	author mcalabre;	state Exp;
branches;
next	8.2.1.7;

8.2.1.7
date	2024.05.10.14.37.01;	author mcalabre;	state Exp;
branches;
next	;

8.3.1.1
date	2024.05.13.16.35.39;	author mcalabre;	state Exp;
branches;
next	8.3.1.2;

8.3.1.2
date	2024.07.09.07.56.06;	author mcalabre;	state Exp;
branches;
next	;

8.4.1.1
date	2024.10.28.13.58.41;	author mcalabre;	state Exp;
branches;
next	8.4.1.2;

8.4.1.2
date	2025.12.06.13.37.16;	author mcalabre;	state Exp;
branches;
next	;

8.5.1.1
date	2025.12.06.14.05.15;	author mcalabre;	state Exp;
branches;
next	8.5.1.2;

8.5.1.2
date	2026.03.29.13.36.16;	author mcalabre;	state Exp;
branches;
next	;

8.6.1.1
date	2026.03.29.14.19.26;	author mcalabre;	state Exp;
branches;
next	8.6.1.2;

8.6.1.2
date	2026.04.24.04.00.32;	author mcalabre;	state Exp;
branches;
next	8.6.1.3;

8.6.1.3
date	2026.04.26.12.45.56;	author mcalabre;	state Exp;
branches;
next	8.6.1.4;

8.6.1.4
date	2026.05.11.11.27.30;	author mcalabre;	state Exp;
branches;
next	;


desc
@Implementation of WCS tabular coordinates (-TAB).
@


8.7
log
@WCSLIB 8.7
@
text
@/*============================================================================
  WCSLIB 8.7 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2026, Mark Calabretta

  This file is part of WCSLIB.

  WCSLIB is free software: you can redistribute it and/or modify it under the
  terms of the GNU Lesser General Public License as published by the Free
  Software Foundation, either version 3 of the License, or (at your option)
  any later version.

  WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  more details.

  You should have received a copy of the GNU Lesser General Public License
  along with WCSLIB.  If not, see http://www.gnu.org/licenses.

  Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
  http://www.atnf.csiro.au/computing/software/wcs
  $Id: tab.c,v 8.6.1.4 2026/05/11 11:27:30 mcalabre Exp mcalabre $
*===========================================================================*/

#include <limits.h>
#include <math.h>
#include <stdio.h>
#include <stddef.h>
#include <stdlib.h>
#include <string.h>

#include "wcserr.h"
#include "wcsmath.h"
#include "wcsprintf.h"
#include "wcsutil.h"
#include "tab.h"

// Map status return value to message.
const char *tab_errmsg[] = {
  "Success",
  "Null tabprm pointer passed",
  "Memory allocation failed",
  "Invalid tabular parameters",
  "One or more of the x coordinates were invalid",
  "One or more of the world coordinates were invalid"};

static const int TABSET = 137;

// Convenience macro for invoking wcserr_set().
#define TAB_ERRMSG(status) WCSERR_SET(status), tab_errmsg[status]

//----------------------------------------------------------------------------

int tabini(int alloc, int M, const int K[], struct tabprm *tab)

{
  static const char *function = "tabini";

  if (tab == 0x0) return TABERR_NULL_POINTER;

  // Initialize error message handling.
  if (tab->flag == -1) {
    tab->err = 0x0;
  }
  struct wcserr **err = &(tab->err);
  wcserr_clear(err);


  if (M <= 0) {
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "M must be positive, got %d", M);
  }

  // Determine the total number of elements in the coordinate array.
  int N;
  if (K) {
    N = M;

    for (int m = 0; m < M; m++) {
      if (K[m] < 0) {
        return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
          "Invalid tabular parameters: Each element of K must be "
          "non-negative, got %d", K[m]);
      }

      if (N < INT_MAX / K[m]) {
        N *= K[m];
      } else {
        return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
          "Invalid tabular parameters: No. elements in coordinate "
          "array exceeds INT_MAX");
      }
    }

  } else {
    // Axis lengths as yet unknown.
    N = 0;
  }


  // Initialize memory management.
  if (tab->flag == -1 || tab->m_flag != TABSET) {
    if (tab->flag == -1) {
      tab->sense   = 0x0;
      tab->p0      = 0x0;
      tab->delta   = 0x0;
      tab->extrema = 0x0;
      tab->set_M   = 0;
    }

    tab->m_flag  = 0;
    tab->m_M     = 0;
    tab->m_N     = 0;
    tab->m_K     = 0x0;
    tab->m_map   = 0x0;
    tab->m_crval = 0x0;
    tab->m_index = 0x0;
    tab->m_indxs = 0x0;
    tab->m_coord = 0x0;

  } else {
    // Clear any outstanding signals set by wcstab().
    for (int m = 0; m < tab->m_M; m++) {
      if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0;
    }

    if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0;
  }


  // Allocate memory for arrays if required.
  if (alloc ||
     tab->K == 0x0 ||
     tab->map == 0x0 ||
     tab->crval == 0x0 ||
     tab->index == 0x0 ||
     tab->coord == 0x0) {

    // Was sufficient allocated previously?
    if (tab->m_flag == TABSET && (tab->m_M < M || tab->m_N < N)) {
      // No, free it.
      tabfree(tab);
    }

    if (alloc || tab->K == 0x0) {
      if (tab->m_K) {
        // In case the caller fiddled with it.
        tab->K = tab->m_K;

      } else {
        if (!(tab->K = calloc(M, sizeof(int)))) {
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_K = tab->K;
      }
    }

    if (alloc || tab->map == 0x0) {
      if (tab->m_map) {
        // In case the caller fiddled with it.
        tab->map = tab->m_map;

      } else {
        if (!(tab->map = calloc(M, sizeof(int)))) {
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_map = tab->map;
      }
    }

    if (alloc || tab->crval == 0x0) {
      if (tab->m_crval) {
        // In case the caller fiddled with it.
        tab->crval = tab->m_crval;

      } else {
        if (!(tab->crval = calloc(M, sizeof(double)))) {
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_crval = tab->crval;
      }
    }

    if (alloc || tab->index == 0x0) {
      if (tab->m_index) {
        // In case the caller fiddled with it.
        tab->index = tab->m_index;

      } else {
        if (!(tab->index = (double **)calloc(M, sizeof(double *)))) {
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_N = N;
        tab->m_index = tab->index;

        if (!(tab->m_indxs = (double **)calloc(M, sizeof(double *)))) {
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
        }

        // Recall that calloc() initializes these pointers to zero.
        if (K) {
          for (int m = 0; m < M; m++) {
            if (K[m]) {
              if (!(tab->index[m] = calloc(K[m], sizeof(double)))) {
                return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
              }

              tab->m_indxs[m] = tab->index[m];
            }
          }
        }
      }
    }

    if (alloc || tab->coord == 0x0) {
      if (tab->m_coord) {
        // In case the caller fiddled with it.
        tab->coord = tab->m_coord;

      } else if (N) {
        if (!(tab->coord = calloc(N, sizeof(double)))) {
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_N = N;
        tab->m_coord = tab->coord;
      }
    }
  }

  tab->M = M;

  // Set defaults.
  for (int m = 0; m < M; m++) {
    tab->map[m] = -1;
    tab->crval[m] = 0.0;

    if (K) {
      tab->K[m] = K[m];
      double *dp;
      if ((dp = tab->index[m])) {
        // Table indexes are 1-relative.
        for (int k = 1; k <= K[m]; k++) {
          *(dp++) = k;
        }
      }
    } else {
      tab->K[m] = 0;
    }
  }

  // Initialize the coordinate array.
  for (double *dp = tab->coord; dp < tab->coord + N; dp++) {
    *dp = UNDEFINED;
  }

  tab->flag = 0;

  return 0;
}

//----------------------------------------------------------------------------

int tabmem(struct tabprm *tab)

{
  static const char *function = "tabmem";

  if (tab == 0x0) return TABERR_NULL_POINTER;
  struct wcserr **err = &(tab->err);

  if (tab->M == 0 || tab->K == 0x0) {
    // Should have been set by this time.
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
  }


  int M = tab->M;
  int N = M;
  for (int m = 0; m < M; m++) {
    if (tab->K[m] < 0) {
      return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
        "Invalid tabular parameters: Each element of K must be "
        "non-negative, got K[%d] = %d", m, tab->K[m]);
    }

    N *= tab->K[m];
  }


  if (tab->m_M == 0) {
    tab->m_M = M;
  } else if (tab->m_M < M) {
    // Only possible if the user changed M.
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "tabprm struct inconsistent");
  }

  if (tab->m_N == 0) {
    tab->m_N = N;
  } else if (tab->m_N < N) {
    // Only possible if the user changed K[].
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "tabprm struct inconsistent");
  }

  if (tab->m_K == 0x0) {
    if ((tab->m_K = tab->K)) {
      tab->m_flag = TABSET;
    }
  }

  if (tab->m_map == 0x0) {
    if ((tab->m_map = tab->map)) {
      tab->m_flag = TABSET;
    }
  }

  if (tab->m_crval == 0x0) {
    if ((tab->m_crval = tab->crval)) {
      tab->m_flag = TABSET;
    }
  }

  if (tab->m_index == 0x0) {
    if ((tab->m_index = tab->index)) {
      tab->m_flag = TABSET;
    }
  }

  // Check memory allocation, balm for static code analysers.
  if (tab->index == 0x0) {
    // Not ppossible if tabini() has been called.
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null index in tabprm struct");
  }

  for (int m = 0; m < tab->m_M; m++) {
    if (tab->m_indxs[m] == 0x0 || tab->m_indxs[m] == (double *)0x1) {
      if ((tab->m_indxs[m] = tab->index[m])) {
        tab->m_flag = TABSET;
      }
    }
  }

  if (tab->m_coord == 0x0 || tab->m_coord == (double *)0x1) {
    if ((tab->m_coord = tab->coord)) {
      tab->m_flag = TABSET;
    }
  }

  tab->flag = 0;

  return 0;
}

//----------------------------------------------------------------------------

int tabcpy(int alloc, const struct tabprm *tabsrc, struct tabprm *tabdst)

{
  static const char *function = "tabcpy";

  if (tabsrc == 0x0) return TABERR_NULL_POINTER;
  if (tabdst == 0x0) return TABERR_NULL_POINTER;
  struct wcserr **err = &(tabdst->err);

  int M = tabsrc->M;
  if (M <= 0) {
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "M must be positive, got %d", M);
  }

  int status;
  if ((status = tabini(alloc, M, tabsrc->K, tabdst))) {
    return status;
  }

  int N = M;
  for (int m = 0; m < M; m++) {
    tabdst->map[m]   = tabsrc->map[m];
    tabdst->crval[m] = tabsrc->crval[m];
    N *= tabsrc->K[m];
  }

  double *dstp, *srcp;
  for (int m = 0; m < M; m++) {
    if ((srcp = tabsrc->index[m])) {
      dstp = tabdst->index[m];
      for (int k = 0; k < tabsrc->K[m]; k++) {
        *(dstp++) = *(srcp++);
      }
    } else {
      if (tabdst->m_indxs && tabdst->m_indxs[m]) {
        free(tabdst->m_indxs[m]);
        tabdst->index[m]   = 0x0;
        tabdst->m_indxs[m] = 0x0;
      }
    }
  }

  srcp = tabsrc->coord;
  dstp = tabdst->coord;
  for (int n = 0; n < N; n++) {
    *(dstp++) = *(srcp++);
  }

  return 0;
}

//----------------------------------------------------------------------------

int tabcmp(
  int dummy,
  double tol,
  const struct tabprm *tab1,
  const struct tabprm *tab2,
  int *equal)

{
  // Avert nuisance compiler warnings about unused parameters.
  (void)dummy;

  if (tab1  == 0x0) return TABERR_NULL_POINTER;
  if (tab2  == 0x0) return TABERR_NULL_POINTER;
  if (equal == 0x0) return TABERR_NULL_POINTER;

  *equal = 0;

  if (tab1->M != tab2->M) {
    return 0;
  }

  int M = tab1->M;

  if (!wcsutil_intEq(M, tab1->K, tab2->K) ||
      !wcsutil_intEq(M, tab1->map, tab2->map) ||
      !wcsutil_dblEq(M, tol, tab1->crval, tab2->crval)) {
    return 0;
  }

  int N = M;
  for (int m = 0; m < M; m++) {
    if (!wcsutil_dblEq(tab1->K[m], tol, tab1->index[m], tab2->index[m])) {
      return 0;
    }

    N *= tab1->K[m];
  }

  if (!wcsutil_dblEq(N, tol, tab1->coord, tab2->coord)) {
    return 0;
  }

  *equal = 1;

  return 0;
}


//----------------------------------------------------------------------------

int tabfree(struct tabprm *tab)

{
  if (tab == 0x0) return TABERR_NULL_POINTER;

  if (tab->flag != -1) {
    // Clear any outstanding signals set by wcstab().
    for (int m = 0; m < tab->m_M; m++) {
      if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0;
    }

    if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0;

    // Free memory allocated by tabini().
    if (tab->m_flag == TABSET) {
      if (tab->K     == tab->m_K)     tab->K = 0x0;
      if (tab->map   == tab->m_map)   tab->map = 0x0;
      if (tab->crval == tab->m_crval) tab->crval = 0x0;
      if (tab->index == tab->m_index) tab->index = 0x0;
      if (tab->coord == tab->m_coord) tab->coord = 0x0;

      if (tab->m_K)     free(tab->m_K);
      if (tab->m_map)   free(tab->m_map);
      if (tab->m_crval) free(tab->m_crval);

      if (tab->m_index) {
        for (int m = 0; m < tab->m_M; m++) {
          if (tab->m_indxs[m]) free(tab->m_indxs[m]);
        }
        free((void *)tab->m_index);
        free((void *)tab->m_indxs);
      }

      if (tab->m_coord) free(tab->m_coord);
    }

    // Free memory allocated by tabset().
    if (tab->sense)   free(tab->sense);
    if (tab->p0)      free(tab->p0);
    if (tab->delta)   free(tab->delta);
    if (tab->extrema) free(tab->extrema);
  }

  tab->m_flag  = 0;
  tab->m_M     = 0;
  tab->m_N     = 0;
  tab->m_K     = 0x0;
  tab->m_map   = 0x0;
  tab->m_crval = 0x0;
  tab->m_index = 0x0;
  tab->m_indxs = 0x0;
  tab->m_coord = 0x0;

  tab->sense   = 0x0;
  tab->p0      = 0x0;
  tab->delta   = 0x0;
  tab->extrema = 0x0;
  tab->set_M   = 0;

  wcserr_clear(&(tab->err));

  tab->flag = 0;

  return 0;
}

//----------------------------------------------------------------------------

int tabsize(const struct tabprm *tab, int sizes[2])

{
  if (tab == 0x0) {
    sizes[0] = sizes[1] = 0;
    return 0;
  }

  // Base size, in bytes.
  sizes[0] = (int)sizeof(struct tabprm);

  // Total size of allocated memory, in bytes.
  sizes[1] = 0;

  int exsizes[2];
  int M = tab->M;

  // tabprm::K[];
  sizes[1] += M * (int)sizeof(int);

  // tabprm::map[];
  sizes[1] += M * (int)sizeof(int);

  // tabprm::crval[];
  sizes[1] += M * (int)sizeof(double);

  // tabprm::index[] and tabprm::m_indxs;
  sizes[1] += 2*M * (int)sizeof(double *);
  for (int m = 0; m < M; m++) {
    if (tab->index[m]) {
      sizes[1] += tab->K[m] * (int)sizeof(double);
    }
  }

  // tabprm::coord[];
  sizes[1] += M * tab->nc * (int)sizeof(double);

  // tab::err[].
  wcserr_size(tab->err, exsizes);
  sizes[1] += exsizes[0] + exsizes[1];

  // The remaining arrays are allocated by tabset().
  if (abs(tab->flag) != TABSET) {
    return 0;
  }

  // tabprm::sense[].
  if (tab->sense) {
    sizes[1] += M * (int)sizeof(int);
  }

  // tabprm::p0[].
  if (tab->p0) {
    sizes[1] += M * (int)sizeof(int);
  }

  // tabprm::delta[].
  if (tab->delta) {
    sizes[1] += M * (int)sizeof(double);
  }

  // tabprm::extrema[].
  int ne = (tab->nc / tab->K[0]) * 2 * M;
  sizes[1] += ne * (int)sizeof(double);

  return 0;
}

//----------------------------------------------------------------------------

int tabenq(const struct tabprm *tab, int enquiry)

{
  // Initialize.
  if (tab == 0x0) return TABERR_NULL_POINTER;

  int answer = 0;

  if (enquiry & TABENQ_MEM) {
    if (tab->m_flag != TABSET) return 0;
    answer = 1;
  }

  if (enquiry & TABENQ_SET) {
    if (abs(tab->flag) != TABSET) return 0;
    answer = 1;
  }

  if (enquiry & TABENQ_BYP) {
    if (tab->flag != 1 && tab->flag != -TABSET) return 0;
    answer = 1;
  }

  return answer;
}

//----------------------------------------------------------------------------

int tabprt(const struct tabprm *tab)

{
  char   text[128], *tpe = text + 128;
  double *dp;

  if (tab == 0x0) return TABERR_NULL_POINTER;

  if (abs(tab->flag) != TABSET) {
    wcsprintf("The tabprm struct is UNINITIALIZED.\n");
    return 0;
  }

  // Parameters supplied...
  wcsprintf("       flag: %d\n", tab->flag);
  wcsprintf("          M: %d\n", tab->M);

  // ...array dimensions.
  WCSPRINTF_PTR("          K: ", tab->K, "\n");
  wcsprintf("            ");
  for (int m = 0; m < tab->M; m++) {
    wcsprintf("%6d", tab->K[m]);
  }
  wcsprintf("\n");

  // ...map vector.
  WCSPRINTF_PTR("        map: ", tab->map, "\n");
  wcsprintf("            ");
  for (int m = 0; m < tab->M; m++) {
    wcsprintf("%6d", tab->map[m]);
  }
  wcsprintf("\n");

  // ...reference index value.
  WCSPRINTF_PTR("      crval: ", tab->crval, "\n");
  wcsprintf("            ");
  for (int m = 0; m < tab->M; m++) {
    wcsprintf("  %#- 11.5g", tab->crval[m]);
  }
  wcsprintf("\n");

  // ...index vectors.
  WCSPRINTF_PTR("      index: ", tab->index, "\n");

  if (tab->index != 0x0) {
    for (int m = 0; m < tab->M; m++) {
      wcsprintf("   index[%d]: ", m);
      WCSPRINTF_PTR("", tab->index[m], "");
      if (tab->index[m]) {
        for (int k = 0; k < tab->K[m]; k++) {
          if (k%5 == 0) {
            wcsprintf("\n            ");
          }
          wcsprintf("  %#- 11.5g", tab->index[m][k]);
        }
      }
      wcsprintf("\n");
    }
  }

  // ...coordinate array.
  WCSPRINTF_PTR("      coord: ", tab->coord, "\n");
  if ((dp = tab->coord)) {
    for (int n = 0; n < tab->nc; n++) {
      // Array index.
      int j = n;
      char *tp = text;
      *tp = '\0';
      for (int m = 0; m < tab->M; m++) {
        tp += strlen(tp);
        size_t tsize = tpe - tp;
        int nd = (tab->K[m] < 10) ? 1 : 2;
        snprintf(tp, tsize, ",%*d", nd, j % tab->K[m] + 1);
        j /= tab->K[m];
      }

      wcsprintf("             (*%s)", text);
      for (int m = 0; m < tab->M; m++) {
        wcsprintf("  %#- 11.5g", *(dp++));
      }
      wcsprintf("\n");
    }
  }

  // Derived values.
  wcsprintf("         nc: %d\n", tab->nc);

  WCSPRINTF_PTR("      sense: ", tab->sense, "\n");
  if (tab->sense) {
    wcsprintf("            ");
    for (int m = 0; m < tab->M; m++) {
      wcsprintf("%6d", tab->sense[m]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("         p0: ", tab->p0, "\n");
  if (tab->p0) {
    wcsprintf("            ");
    for (int m = 0; m < tab->M; m++) {
      wcsprintf("%6d", tab->p0[m]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      delta: ", tab->delta, "\n");
  if (tab->delta) {
    wcsprintf("            ");
    for (int m = 0; m < tab->M; m++) {
      wcsprintf("  %#- 11.5g", tab->delta[m]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("    extrema: ", tab->extrema, "\n");
  if ((dp = tab->extrema)) {
    for (int n = 0; n < tab->nc/tab->K[0]; n++) {
      // Array index.
      int j = n;
      char *tp = text;
      *tp = '\0';
      for (int m = 1; m < tab->M; m++) {
        tp += strlen(tp);
        size_t tsize = tpe - tp;
        int nd = (tab->K[m] < 10) ? 1 : 2;
        snprintf(tp, tsize, ",%*d", nd, j % tab->K[m] + 1);
        j /= tab->K[m];
      }

      wcsprintf("             (*,*%s)", text);
      for (int m = 0; m < 2*tab->M; m++) {
        if (m == tab->M) wcsprintf("->  ");
        wcsprintf("  %#- 11.5g", *(dp++));
      }
      wcsprintf("\n");
    }
  }

  // Error handling.
  WCSPRINTF_PTR("        err: ", tab->err, "\n");
  if (tab->err) {
    wcserr_prt(tab->err, "             ");
  }

  // Memory management.
  wcsprintf("     m_flag: %d\n", tab->m_flag);
  wcsprintf("        m_M: %d\n", tab->m_M);
  wcsprintf("        m_N: %d\n", tab->m_N);

  WCSPRINTF_PTR("        m_K: ", tab->m_K, "");
  if (tab->m_K == tab->K) wcsprintf("  (= K)");
  wcsprintf("\n");

  WCSPRINTF_PTR("      m_map: ", tab->m_map, "");
  if (tab->m_map == tab->map) wcsprintf("  (= map)");
  wcsprintf("\n");

  WCSPRINTF_PTR("    m_crval: ", tab->m_crval, "");
  if (tab->m_crval == tab->crval) wcsprintf("  (= crval)");
  wcsprintf("\n");

  WCSPRINTF_PTR("    m_index: ", tab->m_index, "");
  if (tab->m_index == tab->index) wcsprintf("  (= index)");
  wcsprintf("\n");
  for (int m = 0; m < tab->M; m++) {
    wcsprintf(" m_indxs[%d]: ", m);
    WCSPRINTF_PTR("", tab->m_indxs[m], "");
    if (tab->m_indxs[m] == tab->index[m]) wcsprintf("  (= index[%d])", m);
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("    m_coord: ", tab->m_coord, "");
  if (tab->m_coord == tab->coord) wcsprintf("  (= coord)");
  wcsprintf("\n");

  return 0;
}

//----------------------------------------------------------------------------

int tabperr(const struct tabprm *tab, const char *prefix)

{
  if (tab == 0x0) return TABERR_NULL_POINTER;

  if (tab->err) {
    wcserr_prt(tab->err, prefix);
  }

  return 0;
}

//----------------------------------------------------------------------------

int tabset(struct tabprm *tab)

{
  static const char *function = "tabset";

  if (tab == 0x0) return TABERR_NULL_POINTER;
  if (tab->flag == -TABSET) return 0;
  struct wcserr **err = &(tab->err);

  // Check the number of tabular coordinate axes.
  int M = tab->M;
  if (M < 1) {
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "Invalid tabular parameters: M must be positive, got %d", M);
  }

  // Check the axis lengths.
  if (!tab->K) {
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
  }

  tab->nc = 1;
  for (int m = 0; m < M; m++) {
    if (tab->K[m] < 1) {
      return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
        "Invalid tabular parameters: Each element of K must be positive, "
        "got %d", tab->K[m]);
    }

    // Number of coordinate vectors in the coordinate array.
    tab->nc *= tab->K[m];
  }

  // Check that the map vector is sensible.
  if (!tab->map) {
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
  }

  for (int m = 0; m < M; m++) {
    int i = tab->map[m];
    if (i < 0) {
      return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
        "Invalid tabular parameters: Each element of map must be "
        "non-negative, got %d", i);
    }
  }

  // Check memory allocation for the remaining vectors.
  if (!tab->crval || !tab->index || !tab->coord) {
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
  }

  // Take memory if signalled to by wcstab().
  for (int m = 0; m < tab->m_M; m++) {
    if (tab->m_indxs[m] == (double *)0x1 &&
       (tab->m_indxs[m] = tab->index[m])) {
      tab->m_flag = TABSET;
    }
  }

  if (tab->m_coord == (double *)0x1 &&
     (tab->m_coord = tab->coord)) {
    tab->m_flag = TABSET;
  }


  // Allocate memory for work vectors.
  if (abs(tab->flag) != TABSET || tab->set_M < M) {
    // Free memory that may have been allocated previously.
    if (tab->sense)   free(tab->sense);
    if (tab->p0)      free(tab->p0);
    if (tab->delta)   free(tab->delta);
    if (tab->extrema) free(tab->extrema);

    tab->sense   = 0x0;
    tab->p0      = 0x0;
    tab->delta   = 0x0;
    tab->extrema = 0x0;

    // Allocate memory for internal arrays.
    if (!(tab->sense = calloc(M, sizeof(int)))) {
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
    }

    if (!(tab->p0 = calloc(M, sizeof(int)))) {
      free(tab->sense);
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
    }

    if (!(tab->delta = calloc(M, sizeof(double)))) {
      free(tab->sense);
      free(tab->p0);
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
    }

    int ne = (tab->nc / tab->K[0]) * 2 * M;
    if (!(tab->extrema = calloc(ne, sizeof(double)))) {
      free(tab->sense);
      free(tab->p0);
      free(tab->delta);
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
    }

    tab->set_M = M;
  }

  // Check that the index vectors are monotonic.
  int *Km = tab->K;
  for (int m = 0; m < M; m++, Km++) {
    tab->sense[m] = 0;

    if (*Km > 1) {
      double *Psi;
      if ((Psi = tab->index[m]) == 0x0) {
        // Default indexing.
        tab->sense[m] = 1;

      } else {
        for (int k = 0; k < *Km-1; k++) {
          switch (tab->sense[m]) {
          case 0:
            if (Psi[k] < Psi[k+1]) {
              // Monotonic increasing.
              tab->sense[m] = 1;
            } else if (Psi[k] > Psi[k+1]) {
              // Monotonic decreasing.
              tab->sense[m] = -1;
            }
            break;

          case 1:
            if (Psi[k] > Psi[k+1]) {
              // Should be monotonic increasing.
              free(tab->sense);
              free(tab->p0);
              free(tab->delta);
              free(tab->extrema);
              return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
                "Invalid tabular parameters: Index vectors are not "
                "monotonically increasing");
            }
            break;

          case -1:
            if (Psi[k] < Psi[k+1]) {
              // Should be monotonic decreasing.
              free(tab->sense);
              free(tab->p0);
              free(tab->delta);
              free(tab->extrema);
              return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
                "Invalid tabular parameters: Index vectors are not "
                "monotonically decreasing");
            }
            break;
          default:
            // Not possible.
            break;
          }
        }
      }

      if (tab->sense[m] == 0) {
        free(tab->sense);
        free(tab->p0);
        free(tab->delta);
        free(tab->extrema);
        return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
          "Invalid tabular parameters: Index vectors are not monotonic");
      }
    }
  }

  // Find the extremal values of the coordinate elements in each row.
  double *dcrd = tab->coord;
  double *dmin = tab->extrema;
  double *dmax = tab->extrema + M;
  for (int ic = 0; ic < tab->nc; ic += tab->K[0]) {
    for (int m = 0; m < M; m++, dcrd++) {
      if (tab->K[0] > 1) {
        // Extrapolate a little before the start of the row.
        double dPsi;
        double *Psi = tab->index[0];
        if (Psi == 0x0) {
          dPsi = 1.0;
        } else {
          dPsi = Psi[1] - Psi[0];
        }

        double dval = *dcrd;
        if (dPsi != 0.0) {
          dval -= 0.5 * (*(dcrd+M) - *dcrd)/dPsi;
        }

        *(dmax+m) = *(dmin+m) = dval;
      } else {
        *(dmax+m) = *(dmin+m) = *dcrd;
      }
    }

    dcrd -= M;
    for (int i = 0; i < tab->K[0]; i++) {
      for (int m = 0; m < M; m++, dcrd++) {
        if (*(dmax+m) < *dcrd) *(dmax+m) = *dcrd;
        if (*(dmin+m) > *dcrd) *(dmin+m) = *dcrd;

        if (tab->K[0] > 1 && i == tab->K[0]-1) {
          // Extrapolate a little beyond the end of the row.
          double dPsi;
          double *Psi = tab->index[0];
          if (Psi == 0x0) {
            dPsi = 1.0;
          } else {
            dPsi = Psi[i] - Psi[i-1];
          }

          double dval = *dcrd;
          if (dPsi != 0.0) {
            dval += 0.5 * (*dcrd - *(dcrd-M))/dPsi;
          }

          if (*(dmax+m) < dval) *(dmax+m) = dval;
          if (*(dmin+m) > dval) *(dmin+m) = dval;
        }
      }
    }

    dmin += (ptrdiff_t)(2*M);
    dmax += (ptrdiff_t)(2*M);
  }

  tab->flag = (tab->flag == 1) ? -TABSET : TABSET;

  return 0;
}

//----------------------------------------------------------------------------

int tabx2s(
  struct tabprm *tab,
  int ncoord,
  int nelem,
  const double x[],
  double world[],
  int stat[])

{
  static const char *function = "tabx2s";

  int status;

  if (tab == 0x0) return TABERR_NULL_POINTER;
  struct wcserr **err = &(tab->err);

  // Initialize if required.
  if (abs(tab->flag) != TABSET) {
    if ((status = tabset(tab))) return status;
  }

  // This is used a lot.
  int M = tab->M;

  status = 0;
  const double *xp = x;
  double *wp = world;
  int *statp = stat;
  for (int n = 0; n < ncoord; n++) {
    // Determine the indexes.
    int *Km = tab->K;
    for (int m = 0; m < M; m++, Km++) {
      // N.B. psi_m and Upsilon_m are 1-relative FITS indexes.
      int i = tab->map[m];
      double psi_m = *(xp+i) + tab->crval[m];

      double *Psi = tab->index[m];
      double upsilon;
      if (Psi == 0x0) {
        // Default indexing is simple.
        upsilon = psi_m;

      } else {
        // To ease confusion, decrement Psi so that we can use 1-relative
        // C array indexing to match the 1-relative FITS indexing.
        Psi--;

        if (*Km == 1) {
          // Index vector is degenerate.
          if (Psi[1]-0.5 <= psi_m && psi_m <= Psi[1]+0.5) {
            upsilon = psi_m;
          } else {
            *statp = 1;
            status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
            goto next;
          }

        } else {
          // Interpolate in the indexing vector.
	  int k;
          if (tab->sense[m] == 1) {
            // Monotonic increasing index values.
            if (psi_m < Psi[1]) {
              if (Psi[1] - 0.5*(Psi[2]-Psi[1]) <= psi_m) {
                // Allow minor extrapolation.
                k = 1;

              } else {
                // Index is out of range.
                *statp = 1;
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
                goto next;
              }

            } else if (Psi[*Km] < psi_m) {
              if (psi_m <= Psi[*Km] + 0.5*(Psi[*Km]-Psi[*Km-1])) {
                // Allow minor extrapolation.
                k = *Km - 1;

              } else {
                // Index is out of range.
                *statp = 1;
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
                goto next;
              }

            } else {
              for (k = 1; k < *Km; k++) {
                if (psi_m < Psi[k]) {
                  continue;
                }
                if (Psi[k] == psi_m && psi_m < Psi[k+1]) {
                  break;
                }
                if (Psi[k] < psi_m && psi_m <= Psi[k+1]) {
                  break;
                }
              }
            }

          } else {
            // Monotonic decreasing index values.
            if (psi_m > Psi[1]) {
              if (Psi[1] + 0.5*(Psi[1]-Psi[2]) >= psi_m) {
                // Allow minor extrapolation.
                k = 1;

              } else {
                // Index is out of range.
                *statp = 1;
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
                goto next;
              }

            } else if (psi_m < Psi[*Km]) {
              if (Psi[*Km] - 0.5*(Psi[*Km-1]-Psi[*Km]) <= psi_m) {
                // Allow minor extrapolation.
                k = *Km - 1;

              } else {
                // Index is out of range.
                *statp = 1;
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
                goto next;
              }

            } else {
              for (k = 1; k < *Km; k++) {
                if (psi_m > Psi[k]) {
                  continue;
                }
                if (Psi[k] == psi_m && psi_m > Psi[k+1]) {
                  break;
                }
                if (Psi[k] > psi_m && psi_m >= Psi[k+1]) {
                  break;
                }
              }
            }
          }

          upsilon = k + (psi_m - Psi[k]) / (Psi[k+1] - Psi[k]);
        }
      }

      if (upsilon < 0.5 || upsilon > *Km + 0.5) {
        // Index out of range.
        *statp = 1;
        status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
        goto next;
      }

      // Fiducial array indices and fractional offset.
      // p1 is 1-relative while tab::p0 is 0-relative.
      int p1 = (int)floor(upsilon);
      tab->p0[m] = p1 - 1;
      tab->delta[m] = upsilon - p1;

      if (p1 == 0) {
        // Extrapolation below p1 == 1.
        tab->p0[m] += 1;
        tab->delta[m] -= 1.0;
      } else if (p1 == *Km && *Km > 1) {
        // Extrapolation above p1 == K_m.
        tab->p0[m] -= 1;
        tab->delta[m] += 1.0;
      }
    }


    // Now interpolate in the coordinate array; the M-dimensional linear
    // interpolation algorithm is described in Sect. 3.4 of WCS Paper IV.
    for (int m = 0; m < M; m++) {
      int i = tab->map[m];
      *(wp+i) = 0.0;
    }

    // Loop over the 2^M vertices surrounding P.
    int nv = 1 << M;
    for (int iv = 0; iv < nv; iv++) {
      // Locate vertex in the coordinate array and compute its weight.
      ptrdiff_t offset = 0;
      double wgt = 1.0;
      for (int m = M-1; m >= 0; m--) {
        offset *= tab->K[m];
        offset += tab->p0[m];
        if (iv & (1 << m)) {
          if (tab->K[m] > 1) offset++;
          wgt *= tab->delta[m];
        } else {
          wgt *= 1.0 - tab->delta[m];
        }
      }

      if (wgt == 0.0) continue;

      // Add the contribution from this vertex to each element.
      double *coord = tab->coord + offset*M;
      for (int m = 0; m < M; m++) {
        int i = tab->map[m];
        *(wp+i) += *(coord++) * wgt;
      }

      if (wgt == 1.0) break;
    }

    *statp = 0;

next:
    xp += nelem;
    wp += nelem;
    statp++;
  }

  return status;
}

//----------------------------------------------------------------------------

// Helper functions used only by tabs2x().
static int tabedge(struct tabprm *);
static int tabrow(struct tabprm *, const double *);
static int tabvox(struct tabprm *, const double *, int, double **,
                  unsigned int *);

int tabs2x(
  struct tabprm* tab,
  int ncoord,
  int nelem,
  const double world[],
  double x[],
  int stat[])

{
  static const char *function = "tabs2x";

  int status;

  if (tab == 0x0) return TABERR_NULL_POINTER;
  struct wcserr **err = &(tab->err);

  // Initialize if required.
  if (abs(tab->flag) != TABSET) {
    if ((status = tabset(tab))) return status;
  }

  // This is used a lot.
  int M = tab->M;
  if (M < 1) {
    // Won't get past tabset(), balm for static code analysers.
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "Invalid tabular parameters: M must be positive, got %d", M);
  }

  double **tabcoord = 0x0;
  int nv = 0;
  if (1 < M) {
    nv = 1 << M;
    tabcoord = (double **)calloc(nv, sizeof(double *));
  }


  status = 0;
  const double *wp = world;
  double *xp = x;
  int *statp = stat;
  for (int n = 0; n < ncoord; n++) {
    // Locate this coordinate in the coordinate array.
    int edge = 0;
    for (int m = 0; m < M; m++) {
      tab->p0[m] = 0;
    }

    int ic;
    for (ic = 0; ic < tab->nc; ic++) {
      if (tab->p0[0] == 0) {
        // New row, could it contain a solution?
        if (edge || tabrow(tab, wp)) {
          // No, skip it.
          ic += tab->K[0];
          if (1 < M) {
            tab->p0[1]++;
            edge = tabedge(tab);
          }

          // Because ic will be incremented when the loop is reentered.
          ic--;
          continue;
        }
      }

      if (M == 1) {
        // Deal with the one-dimensional case separately for efficiency.
        double w = wp[tab->map[0]];
        if (w == tab->coord[0]) {
          tab->p0[0] = 0;
          tab->delta[0] = 0.0;
          break;

        } else if (ic < tab->nc - 1) {
          if (((tab->coord[ic] <= w && w <= tab->coord[ic+1]) ||
               (tab->coord[ic] >= w && w >= tab->coord[ic+1])) &&
               (tab->index[0] == 0x0 ||
                tab->index[0][ic] != tab->index[0][ic+1])) {
            tab->p0[0] = ic;
            tab->delta[0] = (w - tab->coord[ic]) /
                            (tab->coord[ic+1] - tab->coord[ic]);
            break;
          }
        }

      } else {
        // Multi-dimensional tables are harder.
        if (!edge) {
          // Addresses of the coordinates for each corner of the "voxel".
          for (int iv = 0; iv < nv; iv++) {
            ptrdiff_t offset = 0;
            for (int m = M-1; m >= 0; m--) {
              offset *= tab->K[m];
              offset += tab->p0[m];
              if ((iv & (1 << m)) && (tab->K[m] > 1)) offset++;
            }
            tabcoord[iv] = tab->coord + offset*M;
          }

          if (tabvox(tab, wp, 0, tabcoord, 0x0) == 0) {
            // Found a solution.
            break;
          }
        }

        // Next voxel.
        tab->p0[0]++;
        edge = tabedge(tab);
      }
    }


    if (ic == tab->nc) {
      // Coordinate not found; allow minor extrapolation.
      if (M == 1) {
        // Should there be a solution?
        double w = wp[tab->map[0]];
        if (tab->extrema[0] <= w && w <= tab->extrema[1]) {
          double *dcrd = tab->coord;
          for (int i = 0; i < 2; i++) {
            if (i) dcrd += tab->K[0] - 2;

            double delta = (w - *dcrd) / (*(dcrd+1) - *dcrd);

            if (i == 0) {
              if (-0.5 <= delta && delta <= 0.0) {
                tab->p0[0] = 0;
                tab->delta[0] = delta;
                ic = 0;
                break;
              }
            } else {
              if (1.0 <= delta && delta <= 1.5) {
                tab->p0[0] = tab->K[0] - 1;
                tab->delta[0] = delta - 1.0;
                ic = 0;
              }
            }
          }
        }

      } else {
        // Multi-dimensional tables.
        // >>> TBD <<<
      }
    }


    if (ic == tab->nc) {
      // Coordinate not found.
      *statp = 1;
      status = wcserr_set(TAB_ERRMSG(TABERR_BAD_WORLD));

    } else {
      // Determine the intermediate world coordinates.
      int *Km = tab->K;
      for (int m = 0; m < M; m++, Km++) {
        // N.B. Upsilon_m and psi_m are 1-relative FITS indexes.
        double upsilon = (tab->p0[m] + 1) + tab->delta[m];

        if (upsilon < 0.5 || upsilon > *Km + 0.5) {
          // Index out of range.
          *statp = 1;
          status = wcserr_set(TAB_ERRMSG(TABERR_BAD_WORLD));

        } else {
          // Do inverse lookup of the index vector.
          double *Psi = tab->index[m];
          double psi_m;
          if (Psi == 0x0) {
            // Default indexing.
            psi_m = upsilon;

          } else {
            // Decrement Psi and use 1-relative C array indexing to match the
            // 1-relative FITS indexing.
            Psi--;

            if (*Km == 1) {
              // Degenerate index vector.
              psi_m = Psi[1];
            } else {
              int k = (int)(upsilon);
              psi_m = Psi[k];
              if (k < *Km) {
                psi_m += (upsilon - k) * (Psi[k+1] - Psi[k]);
              }
            }
          }

          xp[tab->map[m]] = psi_m - tab->crval[m];
        }
      }
      *statp = 0;
    }

    wp += nelem;
    xp += nelem;
    statp++;
  }

  if (tabcoord) free((void *)tabcoord);

  return status;
}

/*----------------------------------------------------------------------------
* Convenience routine to check whether tabprm::p0 has been incremented beyond
* the end of an index vector and if so move it to the start of the next one.
* Returns 1 if tabprm::p0 is sitting at the end of any non-degenerate index
* vector.
*---------------------------------------------------------------------------*/

int tabedge(struct tabprm* tab)

{
  int edge = 0;

  for (int m = 0; m < tab->M; m++) {
    if (tab->p0[m] == tab->K[m]) {
      // p0 has been incremented beyond the end of an index vector, point it
      // to the next one.
      tab->p0[m] = 0;
      if (m < tab->M-1) {
        tab->p0[m+1]++;
      }
    } else if (tab->p0[m] == tab->K[m]-1 && tab->K[m] > 1) {
      // p0 is sitting at the end of a non-degenerate index vector.
      edge = 1;
    }
  }

  return edge;
}

/*----------------------------------------------------------------------------
* Quick test to see whether the world coordinate indicated by wp could lie
* somewhere along (or near) the row of the image indexed by tabprm::p0.
* Return 0 if so, 1 otherwise.
*
* tabprm::p0 selects a particular row of the image, p0[0] being ignored (i.e.
* treated as zero).  Adjacent rows that delimit a row of "voxels" are formed
* by incrementing elements other than p0[0] in all binary combinations.  N.B.
* these are not the same as the voxels (pixels) that are indexed by, and
* centred on, integral pixel coordinates in FITS.
*
* To see why it is necessary to examine the adjacent rows, consider the 2-D
* case where the first world coordinate element is constant along each row.
* If the first element of wp has value 0.5, and its value in the row indexed
* by p0 has value 0, and in the next row it has value 1, then it is clear that
* the solution lies in neither row but somewhere between them.  Thus both rows
* will be involved in finding the solution.
*
* tabprm::extrema is the address of the first element of a 1-D array that
* records the minimum and maximum value of each element of the coordinate
* vector in each row of the coordinate array, treated as though it were
* defined as
*
*   double extrema[K_M]...[K_2][2][M]
*
* The minimum is recorded in the first element of the compressed K_1
* dimension, then the maximum.
*---------------------------------------------------------------------------*/

int tabrow(struct tabprm* tab, const double *wp)

{
  const double tol = 1e-10;

  int M = tab->M;

  // The number of corners in a "voxel".  We need examine only half this
  // number of rows.  The extra factor of two will be used to select between
  // the minimal and maximal values in each row.
  unsigned int nv = 1 << M;

  unsigned int eq = 0;
  unsigned int lt = 0;
  unsigned int gt = 0;
  for (unsigned int iv = 0; iv < nv; iv++) {
    // Find the index into tabprm::extrema for this row.
    int offset = 0;
    for (int m = M-1; m > 0; m--) {
      offset *= tab->K[m];
      offset += tab->p0[m];

      // Select the row.
      if (iv & (1 << m)) {
        if (tab->K[m] > 1) offset++;
      }
    }

    // The K_1 dimension has length 2 (see prologue).
    offset *= 2;

    // Select the minimum on even numbered iterations, else the maximum.
    if (iv & 1) offset++;

    // The last dimension has length M (see prologue).
    offset *= M;

    // Address of the extremal elements (min or max) for this row.
    double *cp = tab->extrema + offset;

    // For each coordinate element, we only need to find one row where its
    // minimum value is less than that of wp, and one row where the maximum
    // value is greater.  That doesn't mean that there is a solution, only
    // that there might be.
    for (int m = 0; m < M; m++, cp++) {
      // Apply the axis mapping.
      double w = wp[tab->map[m]];

      // Finally the test itself; set bits in the bitmask.
      if (fabs(*cp - w) < tol) {
        eq |= (1 << m);
      } else if (*cp < w) {
        lt |= (1 << m);
      } else if (*cp > w) {
        gt |= (1 << m);
      }
    }

    // Have all bits been switched on?
    if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
      // A solution could lie within this row of voxels.
      return 0;
    }
  }

  // No solution in this row.
  return 1;
}

/*----------------------------------------------------------------------------
* Does the world coordinate indicated by wp lie within the voxel indexed by
* tabprm::p0?  If so, do a binary chop of the interior of the voxel to find
* it and return 0, with tabprm::delta set to the solution.  Else return 1.
*
* As in tabrow(), a "voxel" is formed by incrementing the elements of
* tabprm::p0 in all binary combinations.  Note that these are not the same as
* the voxels (pixels) that are indexed by, and centred on, integral pixel
* coordinates in FITS.
*
* tabvox() calls itself recursively.  When called from outside, level, being
* the level of recursion, should be given as zero.  tabcoord is an array
* holding the addresses of the coordinates for each corner of the voxel.
* vox is the address of a work array (vox2) used during recursive calls to
* dissect the voxel.  It is ignored when tabvox() is called from outside
* (level == 0).
*
* It is assumed that the image dimensions are no greater than 32.
----------------------------------------------------------------------------*/

int tabvox(
  struct tabprm* tab,
  const double *wp,
  int level,
  double **tabcoord,
  unsigned int *vox)

{
  const double tol = 1e-10;

  int M = tab->M;

  // The number of corners in a voxel.
  unsigned int nv = 1 << M;

  double dv = 1.0;
  for (int i = 0; i < level; i++) {
    dv /= 2.0;
  }

  // Could the coordinate lie within this voxel (level == 0) or sub-voxel
  // (level > 0)?  We use the fact that with linear interpolation the
  // coordinate elements are extremal in a corner and test each one.
  unsigned int lt = 0;
  unsigned int gt = 0;
  unsigned int eq = 0;
  for (unsigned int iv = 0; iv < nv; iv++) {
    // Select a corner of the sub-voxel.
    double coord[32];
    for (int m = 0; m < M; m++) {
      coord[m] = 0.0;
      tab->delta[m] = level ? dv*vox[m] : 0.0;

      if (iv & (1 << m)) {
        tab->delta[m] += dv;
      }
    }

    // Compute the coordinates of this corner of the sub-voxel by linear
    // interpolation using the weighting algorithm described in Sect. 3.4 of
    // WCS Paper IV.
    for (unsigned int jv = 0; jv < nv; jv++) {
      // Find the weight for this corner of the parent voxel.
      double wgt = 1.0;
      for (int m = 0; m < M; m++) {
        if (jv & (1 << m)) {
          wgt *= tab->delta[m];
        } else {
          wgt *= 1.0 - tab->delta[m];
        }
      }

      if (wgt == 0.0) continue;

      // Add its contribution to each coordinate element.
      double *cp = tabcoord[jv];
      for (int m = 0; m < M; m++) {
        coord[m] += *(cp++) * wgt;
      }

      if (wgt == 1.0) break;
    }

    // Coordinate elements are minimal or maximal in a corner.
    unsigned int et = 0;
    for (int m = 0; m < M; m++) {
      // Apply the axis mapping.
      double w = wp[tab->map[m]];

      // Finally the test itself; set bits in the bitmask.
      if (fabs(coord[m] - w) < tol) {
        et |= (1 << m);
      } else if (coord[m] < w) {
        lt |= (1 << m);
      } else if (coord[m] > w) {
        gt |= (1 << m);
      }
    }

    if (et == nv-1) {
      // We've stumbled across a solution in this corner of the sub-voxel.
      return 0;
    }

    eq |= et;
  }

  // Could the coordinate lie within this sub-voxel?
  if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
    // Yes it could, but does it?

    // Is it time to stop the recursion?
    if (level == 31) {
      // We have a solution, squeeze out the last bit of juice.
      dv /= 2.0;
      for (int m = 0; m < M; m++) {
        tab->delta[m] = dv * (2.0*vox[m] + 1.0);
      }

      return 0;
    }

    // Subdivide the sub-voxel and try again for each subdivision.
    for (unsigned int iv = 0; iv < nv; iv++) {
      // Select the subdivision.
      unsigned int vox2[32];
      for (int m = 0; m < M; m++) {
        vox2[m] = level ? 2*vox[m] : 0;
        if (iv & (1 << m)) {
          vox2[m]++;
        }
      }

      // Recurse.
      if (tabvox(tab, wp, level+1, tabcoord, vox2) == 0) {
        return 0;
      }
    }
  }

  // No solution in this sub-voxel.
  return 1;
}
@


8.6
log
@WCSLIB 8.6
@
text
@d2 1
a2 1
  WCSLIB 8.6 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 8.5.1.2 2026/03/29 13:36:16 mcalabre Exp mcalabre $
d25 1
d28 1
d86 7
a92 1
      N *= K[m];
d199 1
a199 1
        if (!(tab->index = calloc(M, sizeof(double *)))) {
d208 1
a208 1
        if (!(tab->m_indxs = calloc(M, sizeof(double *)))) {
d294 1
a294 1
  int N = tab->M;
d299 1
a299 1
        "non-negative, got %d", M);
d346 7
a378 2
  int status;

d389 1
d507 2
a508 2
        free(tab->m_index);
        free(tab->m_indxs);
d555 1
a555 1
  sizes[0] = sizeof(struct tabprm);
d564 1
a564 1
  sizes[1] += M * sizeof(int);
d567 1
a567 1
  sizes[1] += M * sizeof(int);
d570 1
a570 1
  sizes[1] += M * sizeof(double);
d573 1
a573 1
  sizes[1] += 2*M * sizeof(double *);
d576 1
a576 1
      sizes[1] += tab->K[m] * sizeof(double);
d581 1
a581 1
  sizes[1] += M * tab->nc * sizeof(double);
d594 1
a594 1
    sizes[1] += M * sizeof(int);
d599 1
a599 1
    sizes[1] += M * sizeof(int);
d604 1
a604 1
    sizes[1] += M * sizeof(double);
d609 1
a609 1
  sizes[1] += ne * sizeof(double);
d647 1
a647 1
  char   *cp, text[128];
d687 11
a697 7
  for (int m = 0; m < tab->M; m++) {
    wcsprintf("   index[%d]: ", m);
    WCSPRINTF_PTR("", tab->index[m], "");
    if (tab->index[m]) {
      for (int k = 0; k < tab->K[m]; k++) {
        if (k%5 == 0) {
          wcsprintf("\n            ");
a698 1
        wcsprintf("  %#- 11.5g", tab->index[m][k]);
d700 1
a701 1
    wcsprintf("\n");
d706 19
a724 10
  dp = tab->coord;
  for (int n = 0; n < tab->nc; n++) {
    // Array index.
    int j = n;
    cp = text;
    for (int m = 0; m < tab->M; m++) {
      int nd = (tab->K[m] < 10) ? 1 : 2;
      sprintf(cp, ",%*d", nd, j % tab->K[m] + 1);
      j /= tab->K[m];
      cp += strlen(cp);
a725 6

    wcsprintf("             (*%s)", text);
    for (int m = 0; m < tab->M; m++) {
      wcsprintf("  %#- 11.5g", *(dp++));
    }
    wcsprintf("\n");
d759 20
a778 17
  dp = tab->extrema;
  for (int n = 0; n < tab->nc/tab->K[0]; n++) {
    // Array index.
    int j = n;
    cp = text;
    *cp = '\0';
    for (int m = 1; m < tab->M; m++) {
      int nd = (tab->K[m] < 10) ? 1 : 2;
      sprintf(cp, ",%*d", nd, j % tab->K[m] + 1);
      j /= tab->K[m];
      cp += strlen(cp);
    }

    wcsprintf("             (*,*%s)", text);
    for (int m = 0; m < 2*tab->M; m++) {
      if (m == tab->M) wcsprintf("->  ");
      wcsprintf("  %#- 11.5g", *(dp++));
a779 1
    wcsprintf("\n");
d896 1
a896 1
      (tab->m_indxs[m] = tab->index[m])) {
d902 1
a902 1
    (tab->m_coord = tab->coord)) {
d996 3
d1068 2
a1069 2
    dmin += 2*M;
    dmax += 2*M;
d1260 1
a1260 1
      int offset = 0;
d1327 5
d1335 1
a1335 1
  if (M > 1) {
d1337 1
a1337 1
    tabcoord = calloc(nv, sizeof(double *));
d1395 1
a1395 1
            int offset = 0;
d1506 1
a1506 1
  if (tabcoord) free(tabcoord);
@


8.6.1.1
log
@WCSLIB 8.6 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.6 2026/03/29 13:53:56 mcalabre Exp $
@


8.6.1.2
log
@Inconsequential changes prompted by clang-tidy:
 - Use ptrdiff_t for memory address calculations
   (bugprone-implicit-widening-of-multiplication-result).
 - Explicitly cast pointers-to-pointers returned from calloc() or used as
   arguments to free() (bugprone-multi-level-implicit-pointer-conversion).
 - In tabsize(), Explicitly cast return value of sizeof() to int when doing
   memory size calculations (bugprone-narrowing-conversions).
 - Added (empty) default case to a switch statement in tabset()
   (bugprone-switch-missing-default-case).
 - In tabmem() and tabprt(), guard against dereferencing NULL array pointers
   in tabprm, which is only possible if tabini() was not called and would not
   get past tabset(), and similarly in tabs2x()
   (clang-analyzer-core.NullDereference).
 - In tabprt(), replaced use of sprintf() with snprintf()
   (clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling).
Inconsequential change prompted by Claude Code:
 - In tabini(), check that the total number of elements in the coordinate
   array does not exceed INT_MAX.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.6.1.1 2026/03/29 14:19:26 mcalabre Exp mcalabre $
a24 1
#include <limits.h>
a26 1
#include <stddef.h>
d84 1
a84 7
      if (N < INT_MAX / K[m]) {
        N *= K[m];
      } else {
        return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
          "Invalid tabular parameters: No. elements in coordinate "
          "array exceeds INT_MAX");
      }
d191 1
a191 1
        if (!(tab->index = (double **)calloc(M, sizeof(double *)))) {
d200 1
a200 1
        if (!(tab->m_indxs = (double **)calloc(M, sizeof(double *)))) {
d291 1
a291 1
        "non-negative, got K[%d] = %d", m, tab->K[m]);
a337 7
  // Check memory allocation, balm for static code analysers.
  if (tab->index == 0x0) {
    // Not ppossible if tabini() has been called.
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null index in tabprm struct");
  }

d364 2
a375 1
  int status;
d493 2
a494 2
        free((void *)tab->m_index);
        free((void *)tab->m_indxs);
d541 1
a541 1
  sizes[0] = (int)sizeof(struct tabprm);
d550 1
a550 1
  sizes[1] += M * (int)sizeof(int);
d553 1
a553 1
  sizes[1] += M * (int)sizeof(int);
d556 1
a556 1
  sizes[1] += M * (int)sizeof(double);
d559 1
a559 1
  sizes[1] += 2*M * (int)sizeof(double *);
d562 1
a562 1
      sizes[1] += tab->K[m] * (int)sizeof(double);
d567 1
a567 1
  sizes[1] += M * tab->nc * (int)sizeof(double);
d580 1
a580 1
    sizes[1] += M * (int)sizeof(int);
d585 1
a585 1
    sizes[1] += M * (int)sizeof(int);
d590 1
a590 1
    sizes[1] += M * (int)sizeof(double);
d595 1
a595 1
  sizes[1] += ne * (int)sizeof(double);
d633 1
a633 1
  char   text[128], *tpe = text + 128;
d673 7
a679 11

  if (tab->index != 0x0) {
    for (int m = 0; m < tab->M; m++) {
      wcsprintf("   index[%d]: ", m);
      WCSPRINTF_PTR("", tab->index[m], "");
      if (tab->index[m]) {
        for (int k = 0; k < tab->K[m]; k++) {
          if (k%5 == 0) {
            wcsprintf("\n            ");
          }
          wcsprintf("  %#- 11.5g", tab->index[m][k]);
d681 1
a682 1
      wcsprintf("\n");
d684 1
d689 15
a703 19
  if ((dp = tab->coord)) {
    for (int n = 0; n < tab->nc; n++) {
      // Array index.
      int j = n;
      char *tp = text;
      *tp = '\0';
      for (int m = 0; m < tab->M; m++) {
        tp += strlen(tp);
        size_t tsize = tpe - tp;
        int nd = (tab->K[m] < 10) ? 1 : 2;
        snprintf(tp, tsize, ",%*d", nd, j % tab->K[m] + 1);
        j /= tab->K[m];
      }

      wcsprintf("             (*%s)", text);
      for (int m = 0; m < tab->M; m++) {
        wcsprintf("  %#- 11.5g", *(dp++));
      }
      wcsprintf("\n");
d705 1
d739 17
a755 20
  if ((dp = tab->extrema)) {
    for (int n = 0; n < tab->nc/tab->K[0]; n++) {
      // Array index.
      int j = n;
      char *tp = text;
      *tp = '\0';
      for (int m = 1; m < tab->M; m++) {
        tp += strlen(tp);
        size_t tsize = tpe - tp;
        int nd = (tab->K[m] < 10) ? 1 : 2;
        snprintf(tp, tsize, ",%*d", nd, j % tab->K[m] + 1);
        j /= tab->K[m];
      }

      wcsprintf("             (*,*%s)", text);
      for (int m = 0; m < 2*tab->M; m++) {
        if (m == tab->M) wcsprintf("->  ");
        wcsprintf("  %#- 11.5g", *(dp++));
      }
      wcsprintf("\n");
d757 1
d874 1
a874 1
       (tab->m_indxs[m] = tab->index[m])) {
d880 1
a880 1
     (tab->m_coord = tab->coord)) {
a973 2
          default:
            // Not possible.
d1043 2
a1044 2
    dmin += (ptrdiff_t)(2*M);
    dmax += (ptrdiff_t)(2*M);
d1235 1
a1235 1
      ptrdiff_t offset = 0;
a1301 5
  if (M < 1) {
    // Won't get past tabset(), balm for static code analysers.
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "Invalid tabular parameters: M must be positive, got %d", M);
  }
d1305 1
a1305 1
  if (1 < M) {
d1307 1
a1307 1
    tabcoord = (double **)calloc(nv, sizeof(double *));
d1365 1
a1365 1
            ptrdiff_t offset = 0;
d1476 1
a1476 1
  if (tabcoord) free((void *)tabcoord);
@


8.6.1.3
log
@Inconsequential change prompted by cppcheck:
 - Rearranged an assignment in tabmem() to quell a spurious warning
   (duplicateAssignExpression).
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.6.1.2 2026/04/24 04:00:32 mcalabre Exp mcalabre $
d294 1
a294 1
  int N = M;
@


8.6.1.4
log
@Appeased a pedantic compiler warning.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.6.1.3 2026/04/26 12:45:56 mcalabre Exp mcalabre $
a997 1
            break;
@


8.5
log
@WCSLIB 8.5
@
text
@d2 2
a3 2
  WCSLIB 8.5 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2025, Mark Calabretta
d21 2
a22 2
  http://www.atnf.csiro.au/people/Mark.Calabretta
  $Id: tab.c,v 8.4.1.2 2025/12/06 13:37:16 mcalabre Exp mcalabre $
@


8.5.1.1
log
@WCSLIB 8.5 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.5 2025/12/06 13:47:41 mcalabre Exp $
@


8.5.1.2
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2026, Mark Calabretta
d21 2
a22 2
  http://www.atnf.csiro.au/computing/software/wcs
  $Id: tab.c,v 8.5.1.1 2025/12/06 14:05:15 mcalabre Exp mcalabre $
@


8.4
log
@WCSLIB 8.4
@
text
@d2 2
a3 2
  WCSLIB 8.4 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2024, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 8.3.1.2 2024/07/09 07:56:06 mcalabre Exp mcalabre $
@


8.4.1.1
log
@WCSLIB 8.4 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.4 2024/10/28 13:56:16 mcalabre Exp $
@


8.4.1.2
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2025, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 8.4.1.1 2024/10/28 13:58:41 mcalabre Exp mcalabre $
@


8.3
log
@WCSLIB 8.3
@
text
@d2 1
a2 1
  WCSLIB 8.3 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 8.2.1.7 2024/05/10 14:37:01 mcalabre Exp mcalabre $
d892 5
@


8.3.1.1
log
@WCSLIB 8.3 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.3 2024/05/13 16:33:00 mcalabre Exp $
@


8.3.1.2
log
@Set pointers to zero when memory is free'd in case one of the subsequent
calloc() fails.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.3.1.1 2024/05/13 16:35:39 mcalabre Exp mcalabre $
a891 5

    tab->sense   = 0x0;
    tab->p0      = 0x0;
    tab->delta   = 0x0;
    tab->extrema = 0x0;
@


8.2
log
@WCSLIB 8.2
@
text
@d2 2
a3 2
  WCSLIB 8.2 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2023, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 8.1.1.1 2023/07/05 17:15:00 mcalabre Exp mcalabre $
a35 2
const int TABSET = 137;

d45 2
a236 1
  tab->flag = 0;
d263 2
d537 1
a537 1
    return TABERR_SUCCESS;
d574 2
a575 2
  if (tab->flag != TABSET) {
    return TABERR_SUCCESS;
d597 29
a625 1
  return TABERR_SUCCESS;
d638 1
a638 1
  if (tab->flag != TABSET) {
d643 1
d647 1
a647 1
  // Array dimensions.
d655 1
a655 1
  // Map vector.
d663 1
a663 1
  // Reference index value.
d671 1
a671 1
  // Index vectors.
d687 1
a687 1
  // Coordinate array.
d708 1
d760 1
d822 1
d886 1
a886 1
  if (tab->flag != TABSET || tab->set_M < M) {
d1042 1
a1042 1
  tab->flag = TABSET;
d1066 1
a1066 1
  if (tab->flag != TABSET) {
d1074 3
a1076 3
  register const double *xp = x;
  register double *wp = world;
  register int *statp = stat;
d1291 1
a1291 1
  if (tab->flag != TABSET) {
d1307 3
a1309 3
  register const double *wp = world;
  register double *xp = x;
  register int *statp = stat;
@


8.2.1.1
log
@WCSLIB 8.2 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.2 2023/11/16 10:00:29 mcalabre Exp $
@


8.2.1.2
log
@Declared TABSET to be static.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.2.1.1 2023/11/16 10:05:57 mcalabre Exp mcalabre $
d36 2
a45 2

static const int TABSET = 137;
@


8.2.1.3
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2024, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 8.2.1.2 2023/11/29 07:39:44 mcalabre Exp mcalabre $
@


8.2.1.4
log
@Changes required to support bypass mode in tabset().
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.2.1.3 2024/04/02 14:01:58 mcalabre Exp mcalabre $
d237 1
a263 2
  tab->flag = 0;

d536 1
a536 1
    return 0;
d573 2
a574 2
  if (abs(tab->flag) != TABSET) {
    return 0;
d596 1
a596 1
  return 0;
d609 1
a609 1
  if (abs(tab->flag) != TABSET) {
a613 1
  // Parameters supplied...
d617 1
a617 1
  // ...array dimensions.
d625 1
a625 1
  // ...map vector.
d633 1
a633 1
  // ...reference index value.
d641 1
a641 1
  // ...index vectors.
d657 1
a657 1
  // ...coordinate array.
a677 1
  // Derived values.
a728 1
  // Error handling.
a789 1
  if (tab->flag == -TABSET) return 0;
d853 1
a853 1
  if (abs(tab->flag) != TABSET || tab->set_M < M) {
d1009 1
a1009 1
  tab->flag = (tab->flag == 1) ? -TABSET : TABSET;
d1033 1
a1033 1
  if (abs(tab->flag) != TABSET) {
d1041 3
a1043 3
  const double *xp = x;
  double *wp = world;
  int *statp = stat;
d1258 1
a1258 1
  if (abs(tab->flag) != TABSET) {
d1274 3
a1276 3
  const double *wp = world;
  double *xp = x;
  int *statp = stat;
@


8.2.1.5
log
@Added tabenq().
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.2.1.4 2024/05/08 08:58:26 mcalabre Exp mcalabre $
a597 30
}

//----------------------------------------------------------------------------

int tabenq(const struct tabprm *tab, int enquiry)

{
  static const char *function = "tabenq";

  // Initialize.
  if (tab == 0x0) return TABERR_NULL_POINTER;

  int answer = 0;

  if (enquiry & TABENQ_MEM) {
    if (tab->m_flag != TABSET) return 0;
    answer = 1;
  }

  if (enquiry & TABENQ_SET) {
    if (abs(tab->flag) != TABSET) return 0;
    answer = 1;
  }

  if (enquiry & TABENQ_BYP) {
    if (tab->flag != -TABSET) return 0;
    answer = 1;
  }

  return answer;
@


8.2.1.6
log
@Attended to compiler warnings about unused variables.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.2.1.5 2024/05/08 15:15:50 mcalabre Exp mcalabre $
d605 2
@


8.2.1.7
log
@In tabenq(), the tabprm struct is also in bypass mode, though unset, if
disprm::flag == 1.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.2.1.6 2024/05/08 15:39:34 mcalabre Exp mcalabre $
d621 1
a621 1
    if (tab->flag != 1 && tab->flag != -TABSET) return 0;
@


8.1
log
@WCSLIB 8.1
@
text
@d2 1
a2 1
  WCSLIB 8.1 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 8.0.1.1 2023/07/01 06:22:44 mcalabre Exp mcalabre $
@


8.1.1.1
log
@WCSLIB 8.1 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.1 2023/07/05 17:12:07 mcalabre Exp $
@


8.0
log
@WCSLIB 8.0
@
text
@d2 1
a2 1
  WCSLIB 8.0 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.13.1.2 2023/06/15 04:17:19 mcalabre Exp mcalabre $
@


8.0.1.1
log
@WCSLIB 8.0 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 8.0 2023/07/01 06:15:04 mcalabre Exp $
@


7.13
log
@WCSLIB 7.13
@
text
@d2 2
a3 2
  WCSLIB 7.13 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2022, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 7.12.1.1 2022/09/09 05:00:36 mcalabre Exp mcalabre $
@


7.13.1.1
log
@WCSLIB 7.13 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.13 2022/10/07 03:43:35 mcalabre Exp $
@


7.13.1.2
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2023, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 7.13.1.1 2022/10/07 03:45:47 mcalabre Exp mcalabre $
@


7.12
log
@WCSLIB 7.12
@
text
@d2 1
a2 1
  WCSLIB 7.12 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.11.1.1 2022/04/26 06:15:32 mcalabre Exp mcalabre $
@


7.12.1.1
log
@WCSLIB 7.12 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.12 2022/09/09 04:57:58 mcalabre Exp $
@


7.11
log
@WCSLIB 7.11
@
text
@d2 1
a2 1
  WCSLIB 7.11 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.10.1.2 2022/04/26 05:42:08 mcalabre Exp mcalabre $
@


7.11.1.1
log
@WCSLIB 7.11 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.11 2022/04/26 06:13:52 mcalabre Exp $
@


7.10
log
@WCSLIB 7.10
@
text
@d2 1
a2 1
  WCSLIB 7.10 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.9.1.2 2022/04/03 06:17:15 mcalabre Exp mcalabre $
d249 2
a250 1
        for (int k = 0; k < K[m]; k++) {
@


7.10.1.1
log
@WCSLIB 7.10 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.10 2022/04/23 14:25:15 mcalabre Exp $
@


7.10.1.2
log
@In tabini(), the default index array is 1-relative (was 0-relative).
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.10.1.1 2022/04/23 14:26:54 mcalabre Exp mcalabre $
d249 1
a249 2
        // Table indexes are 1-relative.
        for (int k = 1; k <= K[m]; k++) {
@


7.9
log
@WCSLIB 7.9
@
text
@d2 1
a2 1
  WCSLIB 7.9 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.8.1.1 2022/03/25 06:14:14 mcalabre Exp mcalabre $
d392 6
a651 1
      wcsprintf("\n");
d653 1
@


7.9.1.1
log
@WCSLIB 7.9 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.9 2022/03/25 15:14:48 mcalabre Exp $
@


7.9.1.2
log
@In tabcpy(), collapse degenerate table index arrays if they are collapsed in
the source struct.  Minor fix for output formatting in tabprt().
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.9.1.1 2022/03/25 15:16:40 mcalabre Exp mcalabre $
a391 6
    } else {
      if (tabdst->m_indxs && tabdst->m_indxs[m]) {
        free(tabdst->m_indxs[m]);
        tabdst->index[m]   = 0x0;
        tabdst->m_indxs[m] = 0x0;
      }
d646 1
a647 1
    wcsprintf("\n");
@


7.8
log
@WCSLIB 7.8
@
text
@d2 1
a2 1
  WCSLIB 7.8 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.7.1.2 2022/03/25 06:05:59 mcalabre Exp mcalabre $
@


7.8.1.1
log
@WCSLIB 7.8 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.8 2022/03/25 06:11:49 mcalabre Exp $
@


7.7
log
@WCSLIB 7.7
@
text
@d2 2
a3 2
  WCSLIB 7.7 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2021, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 7.6.1.1 2021/04/13 13:00:35 mcalabre Exp mcalabre $
@


7.7.1.1
log
@WCSLIB 7.7 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.7 2021/07/12 06:36:49 mcalabre Exp $
@


7.7.1.2
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2022, Mark Calabretta
d22 1
a22 1
  $Id: tab.c,v 7.7.1.1 2021/07/12 06:38:27 mcalabre Exp mcalabre $
@


7.6
log
@WCSLIB 7.6
@
text
@d2 1
a2 1
  WCSLIB 7.6 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.5.1.4 2021/04/13 09:22:52 mcalabre Exp mcalabre $
@


7.6.1.1
log
@WCSLIB 7.6 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.6 2021/04/13 12:57:01 mcalabre Exp $
@


7.5
log
@WCSLIB 7.5
@
text
@d2 1
a2 1
  WCSLIB 7.5 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.4.1.1 2021/01/31 02:26:24 mcalabre Exp mcalabre $
a56 4
  int k, m, N;
  double *dp;
  struct wcserr **err;

d63 1
a63 1
  err = &(tab->err);
d73 1
d77 1
a77 1
    for (m = 0; m < M; m++) {
d115 1
a115 1
    for (m = 0; m < tab->m_M; m++) {
d206 1
a206 1
          for (m = 0; m < M; m++) {
d241 1
a241 1
  for (m = 0; m < M; m++) {
d247 1
d249 1
a249 1
        for (k = 0; k < K[m]; k++) {
d259 1
a259 1
  for (dp = tab->coord; dp < tab->coord + N; dp++) {
a272 3
  int m, M, N;
  struct wcserr **err;

d274 1
a274 1
  err = &(tab->err);
d283 3
a285 2
  N = M = tab->M;
  for (m = 0; m < M; m++) {
d336 1
a336 1
  for (m = 0; m < tab->m_M; m++) {
d362 1
a362 3
  int k, m, M, n, N, status;
  double *dstp, *srcp;
  struct wcserr **err;
d366 1
a366 1
  err = &(tabdst->err);
d368 1
a368 1
  M = tabsrc->M;
d378 2
a379 2
  N = M;
  for (m = 0; m < M; m++) {
d385 2
a386 1
  for (m = 0; m < M; m++) {
d389 1
a389 1
      for (k = 0; k < tabsrc->K[m]; k++) {
d397 1
a397 1
  for (n = 0; n < N; n++) {
a413 2
  int m, M, N;

d427 1
a427 1
  M = tab1->M;
d431 1
a431 1
      !wcsutil_Eq(M, tol, tab1->crval, tab2->crval)) {
d435 3
a437 3
  N = M;
  for (m = 0; m < M; m++) {
    if (!wcsutil_Eq(tab1->K[m], tol, tab1->index[m], tab2->index[m])) {
d444 1
a444 1
  if (!wcsutil_Eq(N, tol, tab1->coord, tab2->coord)) {
a458 2
  int m;

d463 1
a463 1
    for (m = 0; m < tab->m_M; m++) {
d482 1
a482 1
        for (m = 0; m < tab->m_M; m++) {
d524 70
a597 1
  int    j, k, m, n, nd;
d613 1
a613 1
  for (m = 0; m < tab->M; m++) {
d621 1
a621 1
  for (m = 0; m < tab->M; m++) {
d629 1
a629 1
  for (m = 0; m < tab->M; m++) {
d636 1
a636 1
  for (m = 0; m < tab->M; m++) {
d640 1
a640 1
      for (k = 0; k < tab->K[m]; k++) {
d653 1
a653 1
  for (n = 0; n < tab->nc; n++) {
d655 1
a655 1
    j = n;
d657 2
a658 2
    for (m = 0; m < tab->M; m++) {
      nd = (tab->K[m] < 10) ? 1 : 2;
d665 1
a665 1
    for (m = 0; m < tab->M; m++) {
d676 1
a676 1
    for (m = 0; m < tab->M; m++) {
d685 1
a685 1
    for (m = 0; m < tab->M; m++) {
d694 1
a694 1
    for (m = 0; m < tab->M; m++) {
d702 1
a702 1
  for (n = 0; n < tab->nc/tab->K[0]; n++) {
d704 1
a704 1
    j = n;
d707 2
a708 2
    for (m = 1; m < tab->M; m++) {
      nd = (tab->K[m] < 10) ? 1 : 2;
d715 1
a715 1
    for (m = 0; m < 2*tab->M; m++) {
d747 1
a747 1
  for (m = 0; m < tab->M; m++) {
a781 4
  int i, ic, k, *Km, m, M, ne;
  double *dcrd, *dmax, *dmin, dPsi, dval, *Psi;
  struct wcserr **err;

d783 1
a783 1
  err = &(tab->err);
d786 2
a787 1
  if ((M = tab->M) < 1) {
d799 1
a799 1
  for (m = 0; m < M; m++) {
d816 2
a817 2
  for (m = 0; m < M; m++) {
    i = tab->map[m];
d832 1
a832 1
  for (m = 0; m < tab->m_M; m++) {
d869 1
a869 1
    ne = M * tab->nc * 2 / tab->K[0];
d881 2
a882 2
  Km = tab->K;
  for (m = 0; m < M; m++, Km++) {
d886 1
d892 1
a892 1
        for (k = 0; k < *Km-1; k++) {
d945 5
a949 5
  dcrd = tab->coord;
  dmin = tab->extrema;
  dmax = tab->extrema + M;
  for (ic = 0; ic < tab->nc; ic += tab->K[0]) {
    for (m = 0; m < M; m++, dcrd++) {
d952 2
a953 1
        Psi = tab->index[0];
d960 1
a960 1
        dval = *dcrd;
d972 2
a973 2
    for (i = 0; i < tab->K[0]; i++) {
      for (m = 0; m < M; m++, dcrd++) {
d979 2
a980 1
          Psi = tab->index[0];
d987 1
a987 1
          dval = *dcrd;
d1020 1
a1020 6
  int i, iv, k, *Km, m, M, n, nv, offset, p1, status;
  double *coord, *Psi, psi_m, upsilon, wgt;
  register int *statp;
  register const double *xp;
  register double *wp;
  struct wcserr **err;
d1023 1
a1023 1
  err = &(tab->err);
d1031 1
a1031 1
  M = tab->M;
d1034 4
a1037 4
  xp = x;
  wp = world;
  statp = stat;
  for (n = 0; n < ncoord; n++) {
d1039 2
a1040 2
    Km = tab->K;
    for (m = 0; m < M; m++, Km++) {
d1042 2
a1043 2
      i = tab->map[m];
      psi_m = *(xp+i) + tab->crval[m];
d1045 2
a1046 1
      Psi = tab->index[m];
d1068 1
d1163 1
a1163 1
      p1 = (int)floor(upsilon);
d1181 3
a1183 3
    for (m = 0; m < M; m++) {
     i = tab->map[m];
     *(wp+i) = 0.0;
d1187 2
a1188 2
    nv = 1 << M;
    for (iv = 0; iv < nv; iv++) {
d1190 3
a1192 3
      offset = 0;
      wgt = 1.0;
      for (m = M-1; m >= 0; m--) {
d1206 3
a1208 3
      coord = tab->coord + offset*M;
      for (m = 0; m < M; m++) {
        i = tab->map[m];
d1245 1
a1245 6
  int edge, i, ic, iv, k, *Km, M, m, n, nv, offset, status;
  double *dcrd, delta, *Psi, psi_m, **tabcoord, upsilon;
  register int *statp;
  register const double *wp;
  register double *xp;
  struct wcserr **err;
d1248 1
a1248 1
  err = &(tab->err);
d1256 1
a1256 1
  M = tab->M;
d1258 2
a1259 2
  tabcoord = 0x0;
  nv = 0;
d1267 4
a1270 4
  wp = world;
  xp = x;
  statp = stat;
  for (n = 0; n < ncoord; n++) {
d1272 2
a1273 2
    edge = 0;
    for (m = 0; m < M; m++) {
d1277 1
d1297 2
a1298 1
        if (*wp == tab->coord[0]) {
d1304 2
a1305 2
          if (((tab->coord[ic] <= *wp && *wp <= tab->coord[ic+1]) ||
               (tab->coord[ic] >= *wp && *wp >= tab->coord[ic+1])) &&
d1309 1
a1309 1
            tab->delta[0] = (*wp - tab->coord[ic]) /
d1319 3
a1321 3
          for (iv = 0; iv < nv; iv++) {
            offset = 0;
            for (m = M-1; m >= 0; m--) {
d1346 4
a1349 3
        if (tab->extrema[0] <= *wp && *wp <= tab->extrema[1]) {
          dcrd = tab->coord;
          for (i = 0; i < 2; i++) {
d1352 1
a1352 1
            delta = (*wp - *dcrd) / (*(dcrd+1) - *dcrd);
d1385 2
a1386 2
      Km = tab->K;
      for (m = 0; m < M; m++, Km++) {
d1388 1
a1388 1
        upsilon = (tab->p0[m] + 1) + tab->delta[m];
d1397 2
a1398 1
          Psi = tab->index[m];
d1412 1
a1412 1
              k = (int)(upsilon);
d1420 1
a1420 2
          i = tab->map[m];
          xp[i] = psi_m - tab->crval[m];
d1446 1
a1446 1
  int edge, m;
d1448 1
a1448 2
  edge = 0;
  for (m = 0; m < tab->M; m++) {
a1496 2
  int M, m, offset;
  unsigned int eq, gt, iv, lt, nv;
a1497 1
  double *cp, w;
d1499 1
a1499 1
  M = tab->M;
d1504 1
a1504 1
  nv = 1 << M;
d1506 4
a1509 4
  eq = 0;
  lt = 0;
  gt = 0;
  for (iv = 0; iv < nv; iv++) {
d1511 2
a1512 2
    offset = 0;
    for (m = M-1; m > 0; m--) {
d1532 1
a1532 1
    cp = tab->extrema + offset;
d1538 1
a1538 1
    for (m = 0; m < M; m++, cp++) {
d1540 1
a1540 1
      w = wp[tab->map[m]];
a1590 2
  int i, M, m;
  unsigned int eq, et, gt, iv, jv, lt, nv, vox2[32];
a1591 1
  double coord[32], *cp, dv, w, wgt;
d1593 1
a1593 1
  M = tab->M;
d1596 1
a1596 1
  nv = 1 << M;
d1598 2
a1599 2
  dv = 1.0;
  for (i = 0; i < level; i++) {
d1606 4
a1609 4
  lt = 0;
  gt = 0;
  eq = 0;
  for (iv = 0; iv < nv; iv++) {
d1611 2
a1612 1
    for (m = 0; m < M; m++) {
d1624 1
a1624 1
    for (jv = 0; jv < nv; jv++) {
d1626 2
a1627 2
      wgt = 1.0;
      for (m = 0; m < M; m++) {
d1638 2
a1639 2
      cp = tabcoord[jv];
      for (m = 0; m < M; m++) {
d1647 2
a1648 2
    et = 0;
    for (m = 0; m < M; m++) {
d1650 1
a1650 1
      w = wp[tab->map[m]];
d1678 1
a1678 1
      for (m = 0; m < M; m++) {
d1686 1
a1686 1
    for (iv = 0; iv < nv; iv++) {
d1688 2
a1689 1
      for (m = 0; m < M; m++) {
@


7.5.1.1
log
@WCSLIB 7.5 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.5 2021/03/20 05:54:58 mcalabre Exp $
@


7.5.1.2
log
@Converted to C99-style intermingled variable declarations.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.5.1.1 2021/03/20 05:56:42 mcalabre Exp mcalabre $
d57 4
d67 1
a67 1
  struct wcserr **err = &(tab->err);
a76 1
  int N;
d80 1
a80 1
    for (int m = 0; m < M; m++) {
d118 1
a118 1
    for (int m = 0; m < tab->m_M; m++) {
d209 1
a209 1
          for (int m = 0; m < M; m++) {
d244 1
a244 1
  for (int m = 0; m < M; m++) {
a249 1
      double *dp;
d251 1
a251 1
        for (int k = 0; k < K[m]; k++) {
d261 1
a261 1
  for (double *dp = tab->coord; dp < tab->coord + N; dp++) {
d275 3
d279 1
a279 1
  struct wcserr **err = &(tab->err);
d288 2
a289 3
  int M = tab->M;
  int N = tab->M;
  for (int m = 0; m < M; m++) {
d340 1
a340 1
  for (int m = 0; m < tab->m_M; m++) {
d366 3
a368 1
  int status;
d372 1
a372 1
  struct wcserr **err = &(tabdst->err);
d374 1
a374 1
  int M = tabsrc->M;
d384 2
a385 2
  int N = M;
  for (int m = 0; m < M; m++) {
d391 1
a391 2
  double *dstp, *srcp;
  for (int m = 0; m < M; m++) {
d394 1
a394 1
      for (int k = 0; k < tabsrc->K[m]; k++) {
d402 1
a402 1
  for (int n = 0; n < N; n++) {
d419 2
d434 1
a434 1
  int M = tab1->M;
d442 2
a443 2
  int N = M;
  for (int m = 0; m < M; m++) {
d466 2
d472 1
a472 1
    for (int m = 0; m < tab->m_M; m++) {
d491 1
a491 1
        for (int m = 0; m < tab->m_M; m++) {
d537 1
d553 1
a553 1
  for (int m = 0; m < tab->M; m++) {
d561 1
a561 1
  for (int m = 0; m < tab->M; m++) {
d569 1
a569 1
  for (int m = 0; m < tab->M; m++) {
d576 1
a576 1
  for (int m = 0; m < tab->M; m++) {
d580 1
a580 1
      for (int k = 0; k < tab->K[m]; k++) {
d593 1
a593 1
  for (int n = 0; n < tab->nc; n++) {
d595 1
a595 1
    int j = n;
d597 2
a598 2
    for (int m = 0; m < tab->M; m++) {
      int nd = (tab->K[m] < 10) ? 1 : 2;
d605 1
a605 1
    for (int m = 0; m < tab->M; m++) {
d616 1
a616 1
    for (int m = 0; m < tab->M; m++) {
d625 1
a625 1
    for (int m = 0; m < tab->M; m++) {
d634 1
a634 1
    for (int m = 0; m < tab->M; m++) {
d642 1
a642 1
  for (int n = 0; n < tab->nc/tab->K[0]; n++) {
d644 1
a644 1
    int j = n;
d647 2
a648 2
    for (int m = 1; m < tab->M; m++) {
      int nd = (tab->K[m] < 10) ? 1 : 2;
d655 1
a655 1
    for (int m = 0; m < 2*tab->M; m++) {
d687 1
a687 1
  for (int m = 0; m < tab->M; m++) {
d722 4
d727 1
a727 1
  struct wcserr **err = &(tab->err);
d730 1
a730 2
  int M = tab->M;
  if (M < 1) {
d742 1
a742 1
  for (int m = 0; m < M; m++) {
d759 2
a760 2
  for (int m = 0; m < M; m++) {
    int i = tab->map[m];
d775 1
a775 1
  for (int m = 0; m < tab->m_M; m++) {
d812 1
a812 1
    int ne = M * tab->nc * 2 / tab->K[0];
d824 2
a825 2
  int *Km = tab->K;
  for (int m = 0; m < M; m++, Km++) {
a828 1
      double *Psi;
d834 1
a834 1
        for (int k = 0; k < *Km-1; k++) {
d887 5
a891 5
  double *dcrd = tab->coord;
  double *dmin = tab->extrema;
  double *dmax = tab->extrema + M;
  for (int ic = 0; ic < tab->nc; ic += tab->K[0]) {
    for (int m = 0; m < M; m++, dcrd++) {
d894 1
a894 2
        double dPsi;
        double *Psi = tab->index[0];
d901 1
a901 1
        double dval = *dcrd;
d913 2
a914 2
    for (int i = 0; i < tab->K[0]; i++) {
      for (int m = 0; m < M; m++, dcrd++) {
d920 1
a920 2
          double dPsi;
          double *Psi = tab->index[0];
d927 1
a927 1
          double dval = *dcrd;
d960 6
a965 1
  int status;
d968 1
a968 1
  struct wcserr **err = &(tab->err);
d976 1
a976 1
  int M = tab->M;
d979 4
a982 4
  register const double *xp = x;
  register double *wp = world;
  register int *statp = stat;
  for (int n = 0; n < ncoord; n++) {
d984 2
a985 2
    int *Km = tab->K;
    for (int m = 0; m < M; m++, Km++) {
d987 2
a988 2
      int i = tab->map[m];
      double psi_m = *(xp+i) + tab->crval[m];
d990 1
a990 2
      double *Psi = tab->index[m];
      double upsilon;
a1011 1
	  int k;
d1106 1
a1106 1
      int p1 = (int)floor(upsilon);
d1124 3
a1126 3
    for (int m = 0; m < M; m++) {
      int i = tab->map[m];
      *(wp+i) = 0.0;
d1130 2
a1131 2
    int nv = 1 << M;
    for (int iv = 0; iv < nv; iv++) {
d1133 3
a1135 3
      int offset = 0;
      double wgt = 1.0;
      for (int m = M-1; m >= 0; m--) {
d1149 3
a1151 3
      double *coord = tab->coord + offset*M;
      for (int m = 0; m < M; m++) {
        int i = tab->map[m];
d1188 6
a1193 1
  int status;
d1196 1
a1196 1
  struct wcserr **err = &(tab->err);
d1204 1
a1204 1
  int M = tab->M;
d1206 2
a1207 2
  double **tabcoord = 0x0;
  int nv = 0;
d1215 4
a1218 4
  register const double *wp = world;
  register double *xp = x;
  register int *statp = stat;
  for (int n = 0; n < ncoord; n++) {
d1220 2
a1221 2
    int edge = 0;
    for (int m = 0; m < M; m++) {
a1224 1
    int ic;
d1265 3
a1267 3
          for (int iv = 0; iv < nv; iv++) {
            int offset = 0;
            for (int m = M-1; m >= 0; m--) {
d1293 2
a1294 2
          double *dcrd = tab->coord;
          for (int i = 0; i < 2; i++) {
d1297 1
a1297 1
            double delta = (*wp - *dcrd) / (*(dcrd+1) - *dcrd);
d1330 2
a1331 2
      int *Km = tab->K;
      for (int m = 0; m < M; m++, Km++) {
d1333 1
a1333 1
        double upsilon = (tab->p0[m] + 1) + tab->delta[m];
d1342 1
a1342 2
          double *Psi = tab->index[m];
          double psi_m;
d1356 1
a1356 1
              int k = (int)(upsilon);
d1364 2
a1365 1
          xp[tab->map[m]] = psi_m - tab->crval[m];
d1391 1
a1391 1
  int edge = 0;
d1393 2
a1394 1
  for (int m = 0; m < tab->M; m++) {
d1443 2
d1446 1
d1448 1
a1448 1
  int M = tab->M;
d1453 1
a1453 1
  unsigned int nv = 1 << M;
d1455 4
a1458 4
  unsigned int eq = 0;
  unsigned int lt = 0;
  unsigned int gt = 0;
  for (unsigned int iv = 0; iv < nv; iv++) {
d1460 2
a1461 2
    int offset = 0;
    for (int m = M-1; m > 0; m--) {
d1481 1
a1481 1
    double *cp = tab->extrema + offset;
d1487 1
a1487 1
    for (int m = 0; m < M; m++, cp++) {
d1489 1
a1489 1
      double w = wp[tab->map[m]];
d1540 2
d1543 1
d1545 1
a1545 1
  int M = tab->M;
d1548 1
a1548 1
  unsigned int nv = 1 << M;
d1550 2
a1551 2
  double dv = 1.0;
  for (int i = 0; i < level; i++) {
d1558 4
a1561 4
  unsigned int lt = 0;
  unsigned int gt = 0;
  unsigned int eq = 0;
  for (unsigned int iv = 0; iv < nv; iv++) {
d1563 1
a1563 2
    double coord[32];
    for (int m = 0; m < M; m++) {
d1575 1
a1575 1
    for (unsigned int jv = 0; jv < nv; jv++) {
d1577 2
a1578 2
      double wgt = 1.0;
      for (int m = 0; m < M; m++) {
d1589 2
a1590 2
      double *cp = tabcoord[jv];
      for (int m = 0; m < M; m++) {
d1598 2
a1599 2
    unsigned int et = 0;
    for (int m = 0; m < M; m++) {
d1601 1
a1601 1
      double w = wp[tab->map[m]];
d1629 1
a1629 1
      for (int m = 0; m < M; m++) {
d1637 1
a1637 1
    for (unsigned int iv = 0; iv < nv; iv++) {
d1639 1
a1639 2
      unsigned int vox2[32];
      for (int m = 0; m < M; m++) {
@


7.5.1.3
log
@Bug fix in tabs2x() triggered for 1-dimensional tables not on the first axis.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.5.1.2 2021/04/06 15:49:44 mcalabre Exp mcalabre $
d1227 1
a1227 2
        double w = wp[tab->map[0]];
        if (w == tab->coord[0]) {
d1233 2
a1234 2
          if (((tab->coord[ic] <= w && w <= tab->coord[ic+1]) ||
               (tab->coord[ic] >= w && w >= tab->coord[ic+1])) &&
d1238 1
a1238 1
            tab->delta[0] = (w - tab->coord[ic]) /
d1275 1
a1275 2
        double w = wp[tab->map[0]];
        if (tab->extrema[0] <= w && w <= tab->extrema[1]) {
d1280 1
a1280 1
            double delta = (w - *dcrd) / (*(dcrd+1) - *dcrd);
@


7.5.1.4
log
@Added new function tabsize().  wcsutil_Eq() -> wcsutil_dblEq().
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.5.1.3 2021/04/07 04:49:53 mcalabre Exp mcalabre $
d431 1
a431 1
      !wcsutil_dblEq(M, tol, tab1->crval, tab2->crval)) {
d437 1
a437 1
    if (!wcsutil_dblEq(tab1->K[m], tol, tab1->index[m], tab2->index[m])) {
d444 1
a444 1
  if (!wcsutil_dblEq(N, tol, tab1->coord, tab2->coord)) {
a523 70
int tabsize(const struct tabprm *tab, int sizes[2])

{
  if (tab == 0x0) {
    sizes[0] = sizes[1] = 0;
    return TABERR_SUCCESS;
  }

  // Base size, in bytes.
  sizes[0] = sizeof(struct tabprm);

  // Total size of allocated memory, in bytes.
  sizes[1] = 0;

  int exsizes[2];
  int M = tab->M;

  // tabprm::K[];
  sizes[1] += M * sizeof(int);

  // tabprm::map[];
  sizes[1] += M * sizeof(int);

  // tabprm::crval[];
  sizes[1] += M * sizeof(double);

  // tabprm::index[] and tabprm::m_indxs;
  sizes[1] += 2*M * sizeof(double *);
  for (int m = 0; m < M; m++) {
    if (tab->index[m]) {
      sizes[1] += tab->K[m] * sizeof(double);
    }
  }

  // tabprm::coord[];
  sizes[1] += M * tab->nc * sizeof(double);

  // tab::err[].
  wcserr_size(tab->err, exsizes);
  sizes[1] += exsizes[0] + exsizes[1];

  // The remaining arrays are allocated by tabset().
  if (tab->flag != TABSET) {
    return TABERR_SUCCESS;
  }

  // tabprm::sense[].
  if (tab->sense) {
    sizes[1] += M * sizeof(int);
  }

  // tabprm::p0[].
  if (tab->p0) {
    sizes[1] += M * sizeof(int);
  }

  // tabprm::delta[].
  if (tab->delta) {
    sizes[1] += M * sizeof(double);
  }

  // tabprm::extrema[].
  int ne = (tab->nc / tab->K[0]) * 2 * M;
  sizes[1] += ne * sizeof(double);

  return TABERR_SUCCESS;
}

//----------------------------------------------------------------------------

d799 1
a799 1
    int ne = (tab->nc / tab->K[0]) * 2 * M;
@


7.4
log
@WCSLIB 7.4
@
text
@d2 1
a2 1
  WCSLIB 7.4 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: tab.c,v 7.3.1.4 2021/01/28 12:29:30 mcalabre Exp mcalabre $
@


7.4.1.1
log
@WCSLIB 7.4 development branch.
@
text
@d22 1
a22 1
  $Id: tab.c,v 7.4 2021/01/31 02:24:51 mcalabre Exp $
@


7.3
log
@WCSLIB 7.3
@
text
@d2 2
a3 3

  WCSLIB 7.3 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2020, Mark Calabretta
a19 2
  Direct correspondence concerning WCSLIB to mark@@calabretta.id.au

d22 1
a22 1
  $Id: tab.c,v 7.2.1.1 2020/03/09 07:34:50 mcalabre Exp mcalabre $
d38 1
a38 1
/* Map status return value to message. */
d47 1
a47 1
/* Convenience macro for invoking wcserr_set(). */
d50 1
a50 1
/*--------------------------------------------------------------------------*/
d63 1
a63 1
  /* Initialize error message handling. */
d76 1
a76 1
  /* Determine the total number of elements in the coordinate array. */
d91 1
a91 1
    /* Axis lengths as yet unknown. */
d96 1
a96 1
  /* Initialize memory management. */
d117 1
a117 1
    /* Clear any outstanding signals set by wcstab(). */
d126 1
a126 1
  /* Allocate memory for arrays if required. */
d134 1
a134 1
    /* Was sufficient allocated previously? */
d136 1
a136 1
      /* No, free it. */
d142 1
a142 1
        /* In case the caller fiddled with it. */
d158 1
a158 1
        /* In case the caller fiddled with it. */
d174 1
a174 1
        /* In case the caller fiddled with it. */
d190 1
a190 1
        /* In case the caller fiddled with it. */
d207 1
a207 1
        /* Recall that calloc() initializes these pointers to zero. */
d224 1
a224 1
        /* In case the caller fiddled with it. */
d243 1
a243 1
  /* Set defaults. */
d260 1
a260 1
  /* Initialize the coordinate array. */
d268 1
a268 1
/*--------------------------------------------------------------------------*/
d282 1
a282 1
    /* Should have been set by this time. */
d303 1
a303 1
    /* Only possible if the user changed M. */
d311 1
a311 1
    /* Only possible if the user changed K[]. */
d359 1
a359 1
/*--------------------------------------------------------------------------*/
d409 1
a409 1
/*--------------------------------------------------------------------------*/
d421 1
a421 1
  /* Avert nuisance compiler warnings about unused parameters. */
d461 1
a461 1
/*--------------------------------------------------------------------------*/
d471 1
a471 1
    /* Clear any outstanding signals set by wcstab(). */
d478 1
a478 1
    /* Free memory allocated by tabini(). */
d501 1
a501 1
    /* Free memory allocated by tabset(). */
d531 1
a531 1
/*--------------------------------------------------------------------------*/
d550 1
a550 1
  /* Array dimensions. */
d558 1
a558 1
  /* Map vector. */
d566 1
a566 1
  /* Reference index value. */
d574 1
a574 1
  /* Index vectors. */
d590 1
a590 1
  /* Coordinate array. */
d594 1
a594 1
    /* Array index. */
d643 1
a643 1
    /* Array index. */
d667 1
a667 1
  /* Memory management. */
d701 1
a701 1
/*--------------------------------------------------------------------------*/
d715 1
a715 1
/*--------------------------------------------------------------------------*/
d729 1
a729 1
  /* Check the number of tabular coordinate axes. */
d735 1
a735 1
  /* Check the axis lengths. */
d749 1
a749 1
    /* Number of coordinate vectors in the coordinate array. */
d753 1
a753 1
  /* Check that the map vector is sensible. */
d768 1
a768 1
  /* Check memory allocation for the remaining vectors. */
d774 1
a774 1
  /* Take memory if signalled to by wcstab(). */
d788 1
a788 1
  /* Allocate memory for work vectors. */
d790 1
a790 1
    /* Free memory that may have been allocated previously. */
d796 1
a796 1
    /* Allocate memory for internal arrays. */
d823 1
a823 1
  /* Check that the index vectors are monotonic. */
d830 1
a830 1
        /* Default indexing. */
d838 1
a838 1
              /* Monotonic increasing. */
d841 1
a841 1
              /* Monotonic decreasing. */
d848 1
a848 1
              /* Should be monotonic increasing. */
d861 1
a861 1
              /* Should be monotonic decreasing. */
d886 1
a886 1
  /* Find the extremal values of the coordinate elements in each row. */
d893 1
a893 1
        /* Extrapolate a little before the start of the row. */
d919 1
a919 1
          /* Extrapolate a little beyond the end of the row. */
d947 1
a947 1
/*--------------------------------------------------------------------------*/
d970 1
a970 1
  /* Initialize if required. */
d975 1
a975 1
  /* This is used a lot. */
d983 1
a983 1
    /* Determine the indexes. */
d986 1
a986 1
      /* N.B. psi_m and Upsilon_m are 1-relative FITS indexes. */
d992 1
a992 1
        /* Default indexing is simple. */
d996 2
a997 2
        /* To ease confusion, decrement Psi so that we can use 1-relative
           C array indexing to match the 1-relative FITS indexing. */
d1001 1
a1001 1
          /* Index vector is degenerate. */
d1011 1
a1011 1
          /* Interpolate in the indexing vector. */
d1013 1
a1013 1
            /* Monotonic increasing index values. */
d1016 1
a1016 1
                /* Allow minor extrapolation. */
d1020 1
a1020 1
                /* Index is out of range. */
d1028 1
a1028 1
                /* Allow minor extrapolation. */
d1032 1
a1032 1
                /* Index is out of range. */
d1053 1
a1053 1
            /* Monotonic decreasing index values. */
d1056 1
a1056 1
                /* Allow minor extrapolation. */
d1060 1
a1060 1
                /* Index is out of range. */
d1068 1
a1068 1
                /* Allow minor extrapolation. */
d1072 1
a1072 1
                /* Index is out of range. */
d1098 1
a1098 1
        /* Index out of range. */
d1104 2
a1105 2
      /* Fiducial array indices and fractional offset.
         p1 is 1-relative while tab::p0 is 0-relative. */
d1111 1
a1111 1
        /* Extrapolation below p1 == 1. */
d1115 1
a1115 1
        /* Extrapolation above p1 == K_m. */
d1122 2
a1123 2
    /* Now interpolate in the coordinate array; the M-dimensional linear  */
    /* interpolation algorithm is described in Sect. 3.4 of WCS Paper IV. */
d1129 1
a1129 1
    /* Loop over the 2^M vertices surrounding P. */
d1132 1
a1132 1
      /* Locate vertex in the coordinate array and compute its weight. */
d1148 1
a1148 1
      /* Add the contribution from this vertex to each element. */
d1169 1
a1169 1
/*--------------------------------------------------------------------------*/
d1171 1
a1171 1
/* Helper functions used only by tabs2x(). */
d1198 1
a1198 1
  /* Initialize if required. */
d1203 1
a1203 1
  /* This is used a lot. */
d1219 1
a1219 1
    /* Locate this coordinate in the coordinate array. */
d1227 1
a1227 1
        /* New row, could it contain a solution? */
d1229 1
a1229 1
          /* No, skip it. */
d1236 1
a1236 1
          /* Because ic will be incremented when the loop is reentered. */
d1243 1
a1243 1
        /* Deal with the one-dimensional case separately for efficiency. */
d1262 1
a1262 1
        /* Multi-dimensional tables are harder. */
d1264 1
a1264 1
          /* Addresses of the coordinates for each corner of the "voxel". */
d1276 1
a1276 1
            /* Found a solution. */
d1281 1
a1281 1
        /* Next voxel. */
d1289 1
a1289 1
      /* Coordinate not found; allow minor extrapolation. */
d1291 1
a1291 1
        /* Should there be a solution? */
d1317 2
a1318 2
        /* Multi-dimensional tables. */
        /* >>> TBD <<< */
d1324 1
a1324 1
      /* Coordinate not found. */
d1329 1
a1329 1
      /* Determine the intermediate world coordinates. */
d1332 1
a1332 1
        /* N.B. Upsilon_m and psi_m are 1-relative FITS indexes. */
d1336 1
a1336 1
          /* Index out of range. */
d1341 1
a1341 1
          /* Do inverse lookup of the index vector. */
d1344 1
a1344 1
            /* Default indexing. */
d1348 2
a1349 2
            /* Decrement Psi and use 1-relative C array indexing to match the
               1-relative FITS indexing. */
d1353 1
a1353 1
              /* Degenerate index vector. */
d1396 2
a1397 2
      /* p0 has been incremented beyond the end of an index vector, point it
         to the next one. */
d1403 1
a1403 1
      /* p0 is sitting at the end of a non-degenerate index vector. */
d1450 3
a1452 3
  /* The number of corners in a "voxel".  We need examine only half this
     number of rows.  The extra factor of two will be used to select between
     the minimal and maximal values in each row. */
d1459 1
a1459 1
    /* Find the index into tabprm::extrema for this row. */
d1465 1
a1465 1
      /* Select the row. */
d1471 1
a1471 1
    /* The K_1 dimension has length 2 (see prologue). */
d1474 1
a1474 1
    /* Select the minimum on even numbered iterations, else the maximum. */
d1477 1
a1477 1
    /* The last dimension has length M (see prologue). */
d1480 1
a1480 1
    /* Address of the extremal elements (min or max) for this row. */
d1483 4
a1486 4
    /* For each coordinate element, we only need to find one row where its
       minimum value is less than that of wp, and one row where the maximum
       value is greater.  That doesn't mean that there is a solution, only
       that there might be. */
d1488 1
a1488 1
      /* Apply the axis mapping. */
d1491 1
a1491 1
      /* Finally the test itself; set bits in the bitmask. */
d1501 1
a1501 1
    /* Have all bits been switched on? */
d1503 1
a1503 1
      /* A solution could lie within this row of voxels. */
d1508 1
a1508 1
  /* No solution in this row. */
d1547 1
a1547 1
  /* The number of corners in a voxel. */
d1555 3
a1557 3
  /* Could the coordinate lie within this voxel (level == 0) or sub-voxel
     (level > 0)?  We use the fact that with linear interpolation the
     coordinate elements are extremal in a corner and test each one. */
d1562 1
a1562 1
    /* Select a corner of the sub-voxel. */
d1572 3
a1574 3
    /* Compute the coordinates of this corner of the sub-voxel by linear
       interpolation using the weighting algorithm described in Sect. 3.4 of
       WCS Paper IV. */
d1576 1
a1576 1
      /* Find the weight for this corner of the parent voxel. */
d1588 1
a1588 1
      /* Add its contribution to each coordinate element. */
d1597 1
a1597 1
    /* Coordinate elements are minimal or maximal in a corner. */
d1600 1
a1600 1
      /* Apply the axis mapping. */
d1603 1
a1603 1
      /* Finally the test itself; set bits in the bitmask. */
d1614 1
a1614 1
      /* We've stumbled across a solution in this corner of the sub-voxel. */
d1621 1
a1621 1
  /* Could the coordinate lie within this sub-voxel? */
d1623 1
a1623 1
    /* Yes it could, but does it? */
d1625 1
a1625 1
    /* Is it time to stop the recursion? */
d1627 1
a1627 1
      /* We have a solution, squeeze out the last bit of juice. */
d1636 1
a1636 1
    /* Subdivide the sub-voxel and try again for each subdivision. */
d1638 1
a1638 1
      /* Select the subdivision. */
d1646 1
a1646 1
      /* Recurse. */
d1653 1
a1653 1
  /* No solution in this sub-voxel. */
@


7.3.1.1
log
@WCSLIB 7.3 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 7.3 2020/06/03 03:37:02 mcalabre Exp $
@


7.3.1.2
log
@Switched to C99 style commenting (i.e. using //) within the code.
@
text
@d2 1
d25 1
a25 1
  $Id: tab.c,v 7.3.1.1 2020/06/03 03:38:10 mcalabre Exp mcalabre $
d41 1
a41 1
// Map status return value to message.
d50 1
a50 1
// Convenience macro for invoking wcserr_set().
d53 1
a53 1
//----------------------------------------------------------------------------
d66 1
a66 1
  // Initialize error message handling.
d79 1
a79 1
  // Determine the total number of elements in the coordinate array.
d94 1
a94 1
    // Axis lengths as yet unknown.
d99 1
a99 1
  // Initialize memory management.
d120 1
a120 1
    // Clear any outstanding signals set by wcstab().
d129 1
a129 1
  // Allocate memory for arrays if required.
d137 1
a137 1
    // Was sufficient allocated previously?
d139 1
a139 1
      // No, free it.
d145 1
a145 1
        // In case the caller fiddled with it.
d161 1
a161 1
        // In case the caller fiddled with it.
d177 1
a177 1
        // In case the caller fiddled with it.
d193 1
a193 1
        // In case the caller fiddled with it.
d210 1
a210 1
        // Recall that calloc() initializes these pointers to zero.
d227 1
a227 1
        // In case the caller fiddled with it.
d246 1
a246 1
  // Set defaults.
d263 1
a263 1
  // Initialize the coordinate array.
d271 1
a271 1
//----------------------------------------------------------------------------
d285 1
a285 1
    // Should have been set by this time.
d306 1
a306 1
    // Only possible if the user changed M.
d314 1
a314 1
    // Only possible if the user changed K[].
d362 1
a362 1
//----------------------------------------------------------------------------
d412 1
a412 1
//----------------------------------------------------------------------------
d424 1
a424 1
  // Avert nuisance compiler warnings about unused parameters.
d464 1
a464 1
//----------------------------------------------------------------------------
d474 1
a474 1
    // Clear any outstanding signals set by wcstab().
d481 1
a481 1
    // Free memory allocated by tabini().
d504 1
a504 1
    // Free memory allocated by tabset().
d534 1
a534 1
//----------------------------------------------------------------------------
d553 1
a553 1
  // Array dimensions.
d561 1
a561 1
  // Map vector.
d569 1
a569 1
  // Reference index value.
d577 1
a577 1
  // Index vectors.
d593 1
a593 1
  // Coordinate array.
d597 1
a597 1
    // Array index.
d646 1
a646 1
    // Array index.
d670 1
a670 1
  // Memory management.
d704 1
a704 1
//----------------------------------------------------------------------------
d718 1
a718 1
//----------------------------------------------------------------------------
d732 1
a732 1
  // Check the number of tabular coordinate axes.
d738 1
a738 1
  // Check the axis lengths.
d752 1
a752 1
    // Number of coordinate vectors in the coordinate array.
d756 1
a756 1
  // Check that the map vector is sensible.
d771 1
a771 1
  // Check memory allocation for the remaining vectors.
d777 1
a777 1
  // Take memory if signalled to by wcstab().
d791 1
a791 1
  // Allocate memory for work vectors.
d793 1
a793 1
    // Free memory that may have been allocated previously.
d799 1
a799 1
    // Allocate memory for internal arrays.
d826 1
a826 1
  // Check that the index vectors are monotonic.
d833 1
a833 1
        // Default indexing.
d841 1
a841 1
              // Monotonic increasing.
d844 1
a844 1
              // Monotonic decreasing.
d851 1
a851 1
              // Should be monotonic increasing.
d864 1
a864 1
              // Should be monotonic decreasing.
d889 1
a889 1
  // Find the extremal values of the coordinate elements in each row.
d896 1
a896 1
        // Extrapolate a little before the start of the row.
d922 1
a922 1
          // Extrapolate a little beyond the end of the row.
d950 1
a950 1
//----------------------------------------------------------------------------
d973 1
a973 1
  // Initialize if required.
d978 1
a978 1
  // This is used a lot.
d986 1
a986 1
    // Determine the indexes.
d989 1
a989 1
      // N.B. psi_m and Upsilon_m are 1-relative FITS indexes.
d995 1
a995 1
        // Default indexing is simple.
d999 2
a1000 2
        // To ease confusion, decrement Psi so that we can use 1-relative
        // C array indexing to match the 1-relative FITS indexing.
d1004 1
a1004 1
          // Index vector is degenerate.
d1014 1
a1014 1
          // Interpolate in the indexing vector.
d1016 1
a1016 1
            // Monotonic increasing index values.
d1019 1
a1019 1
                // Allow minor extrapolation.
d1023 1
a1023 1
                // Index is out of range.
d1031 1
a1031 1
                // Allow minor extrapolation.
d1035 1
a1035 1
                // Index is out of range.
d1056 1
a1056 1
            // Monotonic decreasing index values.
d1059 1
a1059 1
                // Allow minor extrapolation.
d1063 1
a1063 1
                // Index is out of range.
d1071 1
a1071 1
                // Allow minor extrapolation.
d1075 1
a1075 1
                // Index is out of range.
d1101 1
a1101 1
        // Index out of range.
d1107 2
a1108 2
      // Fiducial array indices and fractional offset.
      // p1 is 1-relative while tab::p0 is 0-relative.
d1114 1
a1114 1
        // Extrapolation below p1 == 1.
d1118 1
a1118 1
        // Extrapolation above p1 == K_m.
d1125 2
a1126 2
    // Now interpolate in the coordinate array; the M-dimensional linear
    // interpolation algorithm is described in Sect. 3.4 of WCS Paper IV.
d1132 1
a1132 1
    // Loop over the 2^M vertices surrounding P.
d1135 1
a1135 1
      // Locate vertex in the coordinate array and compute its weight.
d1151 1
a1151 1
      // Add the contribution from this vertex to each element.
d1172 1
a1172 1
//----------------------------------------------------------------------------
d1174 1
a1174 1
// Helper functions used only by tabs2x().
d1201 1
a1201 1
  // Initialize if required.
d1206 1
a1206 1
  // This is used a lot.
d1222 1
a1222 1
    // Locate this coordinate in the coordinate array.
d1230 1
a1230 1
        // New row, could it contain a solution?
d1232 1
a1232 1
          // No, skip it.
d1239 1
a1239 1
          // Because ic will be incremented when the loop is reentered.
d1246 1
a1246 1
        // Deal with the one-dimensional case separately for efficiency.
d1265 1
a1265 1
        // Multi-dimensional tables are harder.
d1267 1
a1267 1
          // Addresses of the coordinates for each corner of the "voxel".
d1279 1
a1279 1
            // Found a solution.
d1284 1
a1284 1
        // Next voxel.
d1292 1
a1292 1
      // Coordinate not found; allow minor extrapolation.
d1294 1
a1294 1
        // Should there be a solution?
d1320 2
a1321 2
        // Multi-dimensional tables.
        // >>> TBD <<<
d1327 1
a1327 1
      // Coordinate not found.
d1332 1
a1332 1
      // Determine the intermediate world coordinates.
d1335 1
a1335 1
        // N.B. Upsilon_m and psi_m are 1-relative FITS indexes.
d1339 1
a1339 1
          // Index out of range.
d1344 1
a1344 1
          // Do inverse lookup of the index vector.
d1347 1
a1347 1
            // Default indexing.
d1351 2
a1352 2
            // Decrement Psi and use 1-relative C array indexing to match the
            // 1-relative FITS indexing.
d1356 1
a1356 1
              // Degenerate index vector.
d1399 2
a1400 2
      // p0 has been incremented beyond the end of an index vector, point it
      // to the next one.
d1406 1
a1406 1
      // p0 is sitting at the end of a non-degenerate index vector.
d1453 3
a1455 3
  // The number of corners in a "voxel".  We need examine only half this
  // number of rows.  The extra factor of two will be used to select between
  // the minimal and maximal values in each row.
d1462 1
a1462 1
    // Find the index into tabprm::extrema for this row.
d1468 1
a1468 1
      // Select the row.
d1474 1
a1474 1
    // The K_1 dimension has length 2 (see prologue).
d1477 1
a1477 1
    // Select the minimum on even numbered iterations, else the maximum.
d1480 1
a1480 1
    // The last dimension has length M (see prologue).
d1483 1
a1483 1
    // Address of the extremal elements (min or max) for this row.
d1486 4
a1489 4
    // For each coordinate element, we only need to find one row where its
    // minimum value is less than that of wp, and one row where the maximum
    // value is greater.  That doesn't mean that there is a solution, only
    // that there might be.
d1491 1
a1491 1
      // Apply the axis mapping.
d1494 1
a1494 1
      // Finally the test itself; set bits in the bitmask.
d1504 1
a1504 1
    // Have all bits been switched on?
d1506 1
a1506 1
      // A solution could lie within this row of voxels.
d1511 1
a1511 1
  // No solution in this row.
d1550 1
a1550 1
  // The number of corners in a voxel.
d1558 3
a1560 3
  // Could the coordinate lie within this voxel (level == 0) or sub-voxel
  // (level > 0)?  We use the fact that with linear interpolation the
  // coordinate elements are extremal in a corner and test each one.
d1565 1
a1565 1
    // Select a corner of the sub-voxel.
d1575 3
a1577 3
    // Compute the coordinates of this corner of the sub-voxel by linear
    // interpolation using the weighting algorithm described in Sect. 3.4 of
    // WCS Paper IV.
d1579 1
a1579 1
      // Find the weight for this corner of the parent voxel.
d1591 1
a1591 1
      // Add its contribution to each coordinate element.
d1600 1
a1600 1
    // Coordinate elements are minimal or maximal in a corner.
d1603 1
a1603 1
      // Apply the axis mapping.
d1606 1
a1606 1
      // Finally the test itself; set bits in the bitmask.
d1617 1
a1617 1
      // We've stumbled across a solution in this corner of the sub-voxel.
d1624 1
a1624 1
  // Could the coordinate lie within this sub-voxel?
d1626 1
a1626 1
    // Yes it could, but does it?
d1628 1
a1628 1
    // Is it time to stop the recursion?
d1630 1
a1630 1
      // We have a solution, squeeze out the last bit of juice.
d1639 1
a1639 1
    // Subdivide the sub-voxel and try again for each subdivision.
d1641 1
a1641 1
      // Select the subdivision.
d1649 1
a1649 1
      // Recurse.
d1656 1
a1656 1
  // No solution in this sub-voxel.
@


7.3.1.3
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2021, Mark Calabretta
d24 1
a24 1
  $Id: tab.c,v 7.3.1.2 2020/08/17 11:19:09 mcalabre Exp mcalabre $
@


7.3.1.4
log
@Removed my email address from the copyright notice.
@
text
@d20 2
d24 1
a24 1
  $Id: tab.c,v 7.3.1.3 2021/01/19 14:09:10 mcalabre Exp mcalabre $
@


7.2
log
@WCSLIB 7.2
@
text
@d3 1
a3 1
  WCSLIB 7.2 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 7.1.1.1 2019/12/31 13:28:19 mcalabre Exp mcalabre $
@


7.2.1.1
log
@WCSLIB 7.2 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 7.2 2020/03/09 07:31:23 mcalabre Exp $
@


7.1
log
@WCSLIB 7.1
@
text
@d3 1
a3 1
  WCSLIB 7.1 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 6.4.1.5 2019/12/31 13:06:14 mcalabre Exp mcalabre $
@


7.1.1.1
log
@WCSLIB 7.1 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 7.1 2019/12/31 13:25:19 mcalabre Exp $
@


6.4
log
@WCSLIB 6.4
@
text
@d3 2
a4 2
  WCSLIB 6.4 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2019, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 6.3.1.1 2019/07/12 07:34:37 mcalabre Exp mcalabre $
d1114 1
d1118 1
d1174 6
a1190 4
  int tabedge(struct tabprm *);
  int tabrow(struct tabprm *, const double *);
  int tabvox(struct tabprm *, const double *, int, double **, unsigned int *);

d1234 4
a1237 2
          tab->p0[1]++;
          edge = tabedge(tab);
d1385 4
a1388 1
* Convenience routine to deal with of edge effects in tabprm::p0.
d1394 1
a1394 1
  int edge, *Km, m;
d1397 4
a1400 5
  Km = tab->K;
  for (m = 0; m < tab->M; m++, Km++) {
    if (tab->p0[m] == *Km) {
      /* p0 has been incremented beyond the end of the row, point it to the
         next one. */
d1402 5
a1406 3
      tab->p0[m+1]++;
    } else if (tab->p0[m] == *Km - 1 && *Km > 1) {
      /* p0 is sitting at the end of a non-degenerate row. */
d1532 1
a1532 1
* It is assumed that the image dimensions are no greater than 16.
d1544 1
a1544 1
  unsigned int eq, et, gt, iv, jv, lt, nv, vox2[16];
d1546 1
a1546 1
  double coord[16], *cp, dv, w, wgt;
@


6.4.1.1
log
@WCSLIB 6.4 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.4 2019/08/15 09:30:18 mcalabre Exp $
@


6.4.1.2
log
@Declare static the three helper functions, tabedge(), tabrow(), and tabvox(),
used by tabs2x().  Increased the number of coordinate axes handled by
tabvox() from 16 to 32.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.4.1.1 2019/08/15 09:31:29 mcalabre Exp mcalabre $
a1171 6
/* Helper functions used only by tabs2x(). */
static int tabedge(struct tabprm *);
static int tabrow(struct tabprm *, const double *);
static int tabvox(struct tabprm *, const double *, int, double **,
                  unsigned int *);

d1183 4
d1522 1
a1522 1
* It is assumed that the image dimensions are no greater than 32.
d1534 1
a1534 1
  unsigned int eq, et, gt, iv, jv, lt, nv, vox2[32];
d1536 1
a1536 1
  double coord[32], *cp, dv, w, wgt;
@


6.4.1.3
log
@Fixed typo in a comment.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.4.1.2 2019/11/29 04:16:06 mcalabre Exp mcalabre $
d1381 1
a1381 1
* Convenience routine to deal with edge effects in tabprm::p0.
@


6.4.1.4
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2020, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 6.4.1.3 2019/12/31 02:16:57 mcalabre Exp mcalabre $
@


6.4.1.5
log
@In tabs2x() and tabedge(), take care not to increment tabprm::p0 beyond the
end of the array.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.4.1.4 2019/12/31 03:28:03 mcalabre Exp mcalabre $
a1113 1
        /* Extrapolation below p1 == 1. */
a1116 1
        /* Extrapolation above p1 == K_m. */
d1232 2
a1233 4
          if (1 < M) {
            tab->p0[1]++;
            edge = tabedge(tab);
          }
d1381 1
a1381 4
* Convenience routine to check whether tabprm::p0 has been incremented beyond
* the end of an index vector and if so move it to the start of the next one.
* Returns 1 if tabprm::p0 is sitting at the end of any non-degenerate index
* vector.
d1387 1
a1387 1
  int edge, m;
d1390 5
a1394 4
  for (m = 0; m < tab->M; m++) {
    if (tab->p0[m] == tab->K[m]) {
      /* p0 has been incremented beyond the end of an index vector, point it
         to the next one. */
d1396 3
a1398 5
      if (m < tab->M-1) {
        tab->p0[m+1]++;
      }
    } else if (tab->p0[m] == tab->K[m]-1 && tab->K[m] > 1) {
      /* p0 is sitting at the end of a non-degenerate index vector. */
@


6.3
log
@WCSLIB 6.3
@
text
@d3 1
a3 1
  WCSLIB 6.3 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 6.2.1.5 2019/07/09 08:49:45 mcalabre Exp mcalabre $
@


6.3.1.1
log
@WCSLIB 6.3 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.3 2019/07/12 07:33:39 mcalabre Exp $
@


6.2
log
@WCSLIB 6.2
@
text
@d3 2
a4 2
  WCSLIB 6.2 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2018, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 6.1.1.1 2018/10/19 08:36:15 mcalabre Exp mcalabre $
d67 3
d71 1
a71 4
  if (tab->flag != -1) {
    if (tab->err) free(tab->err);
  }
  tab->err = 0x0;
d414 6
a419 5
int tabcmp(int dummy,
           double tol,
           const struct tabprm *tab1,
           const struct tabprm *tab2,
           int *equal)
d527 1
a527 4
  if (tab->err) {
    free(tab->err);
    tab->err = 0x0;
  }
@


6.2.1.1
log
@WCSLIB 6.2 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.2 2018/10/20 10:03:13 mcalabre Exp $
@


6.2.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2019, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 6.2.1.1 2018/10/20 10:04:15 mcalabre Exp mcalabre $
@


6.2.1.3
log
@In tabinit() and tabfree(), use wcserr_clear() to free the wcserr struct,
including any memory that may have been allocated to store a message.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.2.1.2 2019/05/10 01:56:50 mcalabre Exp mcalabre $
d69 1
a69 1
    wcserr_clear(err);
d71 1
d526 4
a529 1
  wcserr_clear(&(tab->err));
@


6.2.1.4
log
@Whitespace.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.2.1.3 2019/07/08 03:33:03 mcalabre Exp mcalabre $
d413 5
a417 6
int tabcmp(
  int dummy,
  double tol,
  const struct tabprm *tab1,
  const struct tabprm *tab2,
  int *equal)
@


6.2.1.5
log
@Fixed the initialisation of error message handling in tabini().
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.2.1.4 2019/07/08 05:09:44 mcalabre Exp mcalabre $
d67 3
a69 2
  if (tab->flag == -1) {
    tab->err = 0x0;
a70 2
  err = &(tab->err);
  wcserr_clear(err);
@


6.1
log
@WCSLIB 6.1
@
text
@d3 1
a3 1
  WCSLIB 6.1 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.20.1.1 2018/10/05 05:33:33 mcalabre Exp mcalabre $
@


6.1.1.1
log
@WCSLIB 6.1 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 6.1 2018/10/19 08:35:17 mcalabre Exp $
@


5.20
log
@WCSLIB 5.20
@
text
@d3 1
a3 1
  WCSLIB 5.20 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.19.1.1 2018/07/26 15:41:40 mcalabre Exp mcalabre $
@


5.20.1.1
log
@WCSLIB 5.20 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.20 2018/10/05 05:32:41 mcalabre Exp $
@


5.19
log
@WCSLIB 5.19
@
text
@d3 1
a3 1
  WCSLIB 5.19 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.18.1.2 2018/07/25 01:10:31 mcalabre Exp mcalabre $
@


5.19.1.1
log
@WCSLIB 5.19 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.19 2018/07/26 15:37:04 mcalabre Exp $
@


5.18
log
@WCSLIB 5.18
@
text
@d3 1
a3 1
  WCSLIB 5.18 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.17.1.2 2018/01/10 08:25:34 mcalabre Exp mcalabre $
d422 3
@


5.18.1.1
log
@WCSLIB 5.18 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.18 2018/01/10 08:32:14 mcalabre Exp $
@


5.18.1.2
log
@In tabcmp(), avert nuisance compiler warnings about unused parameters
(gcc -Wunused-parameter).
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.18.1.1 2018/01/10 08:33:04 mcalabre Exp mcalabre $
a421 3

  /* Avert nuisance compiler warnings about unused parameters. */
  (void)dummy;
@


5.17
log
@WCSLIB 5.17
@
text
@d3 2
a4 2
  WCSLIB 5.17 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2017, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 5.16.1.3 2017/09/12 14:21:25 mcalabre Exp mcalabre $
@


5.17.1.1
log
@WCSLIB 5.17 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.17 2017/09/18 08:44:23 mcalabre Exp $
@


5.17.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2018, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 5.17.1.1 2017/09/18 08:45:59 mcalabre Exp mcalabre $
@


5.16
log
@WCSLIB 5.16
@
text
@d3 1
a3 1
  WCSLIB 5.16 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.15.1.2 2017/01/15 04:13:33 mcalabre Exp mcalabre $
d414 1
a414 1
int tabcmp(int cmp,
d1435 2
a1436 2
  int iv, M, m, nv, offset;
  unsigned int eq, gt, lt;
d1532 2
a1533 2
  int i, iv, jv, M, m, nv;
  unsigned int eq, et, gt, lt, vox2[16];
@


5.16.1.1
log
@WCSLIB 5.16 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.16 2017/01/15 04:25:01 mcalabre Exp $
@


5.16.1.2
log
@Renamed the first, unused argument of tabcmp() from "cmp" to "dummy" to make
it clear that it is not (currently) used in this function.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.16.1.1 2017/01/15 04:28:59 mcalabre Exp mcalabre $
d414 1
a414 1
int tabcmp(int dummy,
@


5.16.1.3
log
@Fixed warnings about comparison between signed and unsigned integers in
tabrow() and tabvox().
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.16.1.2 2017/09/12 13:07:57 mcalabre Exp mcalabre $
d1435 2
a1436 2
  int M, m, offset;
  unsigned int eq, gt, iv, lt, nv;
d1532 2
a1533 2
  int i, M, m;
  unsigned int eq, et, gt, iv, jv, lt, nv, vox2[16];
@


5.15
log
@WCSLIB 5.15
@
text
@d3 2
a4 2
  WCSLIB 5.15 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2016, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 5.14.1.1 2016/02/07 10:52:44 mcalabre Exp mcalabre $
@


5.15.1.1
log
@WCSLIB 5.15 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.15 2016/04/05 12:55:10 mcalabre Exp $
@


5.15.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2017, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 5.15.1.1 2016/04/05 12:58:35 mcalabre Exp mcalabre $
@


5.14
log
@WCSLIB 5.14
@
text
@d3 1
a3 1
  WCSLIB 5.14 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.13.1.1 2016/01/26 08:54:32 mcalabre Exp mcalabre $
@


5.14.1.1
log
@WCSLIB 5.14 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.14 2016/02/07 10:49:31 mcalabre Exp $
@


5.13
log
@WCSLIB 5.13
@
text
@d3 1
a3 1
  WCSLIB 5.13 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.12.1.2 2016/01/25 05:17:04 mcalabre Exp mcalabre $
@


5.13.1.1
log
@WCSLIB 5.13 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.13 2016/01/26 08:51:13 mcalabre Exp $
@


5.12
log
@WCSLIB 5.12
@
text
@d3 2
a4 2
  WCSLIB 5.12 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2015, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 5.11.1.1 2015/10/18 09:16:27 mcalabre Exp mcalabre $
@


5.12.1.1
log
@WCSLIB 5.12 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.12 2015/11/15 02:13:00 mcalabre Exp $
@


5.12.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2016, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 5.12.1.1 2015/11/15 02:16:14 mcalabre Exp mcalabre $
@


5.11
log
@WCSLIB 5.11
@
text
@d3 1
a3 1
  WCSLIB 5.11 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.10.1.1 2015/10/09 08:22:35 mcalabre Exp mcalabre $
@


5.11.1.1
log
@WCSLIB 5.11 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.11 2015/10/18 09:13:05 mcalabre Exp $
@


5.10
log
@WCSLIB 5.10
@
text
@d3 1
a3 1
  WCSLIB 5.10 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.9.1.1 2015/07/21 09:28:07 mcalabre Exp mcalabre $
@


5.10.1.1
log
@WCSLIB 5.10 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.10 2015/10/09 08:19:15 mcalabre Exp $
@


5.9
log
@WCSLIB 5.9
@
text
@d3 1
a3 1
  WCSLIB 5.9 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.8.1.1 2015/07/08 11:07:18 mcalabre Exp mcalabre $
@


5.9.1.1
log
@WCSLIB 5.9 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.9 2015/07/21 09:20:01 mcalabre Exp $
@


5.8
log
@WCSLIB 5.8
@
text
@d3 1
a3 1
  WCSLIB 5.8 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.7.1.1 2015/06/29 02:47:24 mcalabre Exp mcalabre $
@


5.8.1.1
log
@WCSLIB 5.8 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.8 2015/07/08 11:03:59 mcalabre Exp $
@


5.7
log
@WCSLIB 5.7
@
text
@d3 1
a3 1
  WCSLIB 5.7 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.6.1.2 2015/06/18 08:13:35 mcalabre Exp mcalabre $
@


5.7.1.1
log
@WCSLIB 5.7 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.7 2015/06/29 02:44:16 mcalabre Exp $
@


5.6
log
@WCSLIB 5.6
@
text
@d3 1
a3 1
  WCSLIB 5.6 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.5.1.1 2015/05/05 13:21:00 mcalabre Exp mcalabre $
d699 14
@


5.6.1.1
log
@WCSLIB 5.6 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.6 2015/06/14 07:11:24 mcalabre Exp $
@


5.6.1.2
log
@Added tabperr().
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.6.1.1 2015/06/14 07:14:44 mcalabre Exp mcalabre $
a698 14

  return 0;
}

/*--------------------------------------------------------------------------*/

int tabperr(const struct tabprm *tab, const char *prefix)

{
  if (tab == 0x0) return TABERR_NULL_POINTER;

  if (tab->err) {
    wcserr_prt(tab->err, prefix);
  }
@


5.5
log
@WCSLIB 5.5
@
text
@d3 1
a3 1
  WCSLIB 5.5 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.4.1.1 2015/04/21 14:44:28 mcalabre Exp mcalabre $
@


5.5.1.1
log
@WCSLIB 5.5 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.5 2015/05/05 13:16:31 mcalabre Exp $
@


5.4
log
@WCSLIB 5.4
@
text
@d3 1
a3 1
  WCSLIB 5.4 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.3.1.1 2015/04/21 02:54:02 mcalabre Exp mcalabre $
@


5.4.1.1
log
@WCSLIB 5.4 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.4 2015/04/21 14:41:05 mcalabre Exp $
@


5.3
log
@WCSLIB 5.3
@
text
@d3 1
a3 1
  WCSLIB 5.3 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.2.1.1 2015/04/15 12:39:14 mcalabre Exp mcalabre $
@


5.3.1.1
log
@WCSLIB 5.3 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.3 2015/04/21 02:50:51 mcalabre Exp $
@


5.2
log
@WCSLIB 5.2
@
text
@d3 1
a3 1
  WCSLIB 5.2 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.1.1.1 2015/04/07 11:01:10 mcalabre Exp mcalabre $
@


5.2.1.1
log
@WCSLIB 5.2 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.2 2015/04/15 12:35:07 mcalabre Exp $
@


5.1
log
@WCSLIB 5.1
@
text
@d3 1
a3 1
  WCSLIB 5.1 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 5.0.1.1 2015/04/05 12:28:00 mcalabre Exp mcalabre $
@


5.1.1.1
log
@WCSLIB 5.1 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.1 2015/04/07 10:56:36 mcalabre Exp $
@


5.0
log
@WCSLIB 5.0
@
text
@d3 1
a3 1
  WCSLIB 5.0 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.25.1.4 2015/04/03 01:34:23 mcalabre Exp mcalabre $
@


5.0.1.1
log
@WCSLIB 5.0 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 5.0 2015/04/05 12:24:59 mcalabre Exp $
@


4.25
log
@WCSLIB 4.25
@
text
@d3 2
a4 2
  WCSLIB 4.25 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2014, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 4.24.1.1 2014/09/18 15:28:09 mcalabre Exp mcalabre $
d68 2
a69 2
  if (tab->err && tab->flag != -1) {
    free(tab->err);
d101 8
a127 8
  if (tab->flag == -1) {
    tab->sense   = 0x0;
    tab->p0      = 0x0;
    tab->delta   = 0x0;
    tab->extrema = 0x0;
    tab->set_M   = 0;
  }

a420 1
  int status = 0;
d572 1
a572 1
    wcsprintf("  %- 11.5g", tab->crval[m]);
d586 1
a586 1
        wcsprintf("  %- 11.5g", tab->index[m][k]);
d608 1
a608 1
      wcsprintf("  %- 11.5g", *(dp++));
d637 1
a637 1
      wcsprintf("  %- 11.5g", tab->delta[m]);
d659 1
a659 1
      wcsprintf("  %- 11.5g", *(dp++));
d1309 1
@


4.25.1.1
log
@WCSLIB 4.25 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.25 2014/12/14 14:29:36 mcalabre Exp $
@


4.25.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2015, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 4.25.1.1 2014/12/14 14:32:45 mcalabre Exp mcalabre $
@


4.25.1.3
log
@In tabini(), fixed the test for deallocating tabprm::err (uncovered by
valgrind).
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.25.1.2 2015/01/06 01:01:06 mcalabre Exp mcalabre $
d68 2
a69 2
  if (tab->flag != -1) {
    if (tab->err) free(tab->err);
d421 1
@


4.25.1.4
log
@Housecleaning in tabini().  Tweaked output formatting in tabprt().
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.25.1.3 2015/03/05 14:37:20 mcalabre Exp mcalabre $
a100 8
    if (tab->flag == -1) {
      tab->sense   = 0x0;
      tab->p0      = 0x0;
      tab->delta   = 0x0;
      tab->extrema = 0x0;
      tab->set_M   = 0;
    }

d120 8
d572 1
a572 1
    wcsprintf("  %#- 11.5g", tab->crval[m]);
d586 1
a586 1
        wcsprintf("  %#- 11.5g", tab->index[m][k]);
d608 1
a608 1
      wcsprintf("  %#- 11.5g", *(dp++));
d637 1
a637 1
      wcsprintf("  %#- 11.5g", tab->delta[m]);
d659 1
a659 1
      wcsprintf("  %#- 11.5g", *(dp++));
a1308 1

@


4.24
log
@WCSLIB 4.24
@
text
@d3 1
a3 1
  WCSLIB 4.24 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.23.1.2 2014/05/22 10:51:36 mcalabre Exp mcalabre $
@


4.24.1.1
log
@WCSLIB 4.24 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.24 2014/09/18 15:25:00 mcalabre Exp $
@


4.23
log
@WCSLIB 4.23
@
text
@d3 1
a3 1
  WCSLIB 4.23 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.22.1.3 2014/05/11 04:06:31 mcalabre Exp mcalabre $
d415 1
d438 1
a438 1
      !wcsutil_Eq(M, tab1->crval, tab2->crval)) {
d444 1
a444 1
    if (!wcsutil_Eq(tab1->K[m], tab1->index[m], tab2->index[m])) {
d451 1
a451 1
  if (!wcsutil_Eq(N, tab1->coord, tab2->coord)) {
@


4.23.1.1
log
@WCSLIB 4.23 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.23 2014/05/13 05:50:51 mcalabre Exp $
@


4.23.1.2
log
@Changed API to tabcmp() to allow a tolerance to be specified for floating-
point comparisons.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.23.1.1 2014/05/13 05:53:49 mcalabre Exp mcalabre $
a414 1
           double tol,
d437 1
a437 1
      !wcsutil_Eq(M, tol, tab1->crval, tab2->crval)) {
d443 1
a443 1
    if (!wcsutil_Eq(tab1->K[m], tol, tab1->index[m], tab2->index[m])) {
d450 1
a450 1
  if (!wcsutil_Eq(N, tol, tab1->coord, tab2->coord)) {
@


4.22
log
@WCSLIB 4.22
@
text
@d3 1
a3 1
  WCSLIB 4.22 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.21.1.1 2014/03/24 05:15:28 mcalabre Exp mcalabre $
d36 1
d411 48
@


4.22.1.1
log
@WCSLIB 4.22 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.22 2014/04/12 15:03:52 mcalabre Exp $
@


4.22.1.2
log
@New function tabcmp() contributed by Michael Droettboom.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.22.1.1 2014/04/12 15:06:32 mcalabre Exp mcalabre $
a35 1
#include "wcsutil.h"
a409 51

/*--------------------------------------------------------------------------*/

int tabcmp(int cmp,
           const struct tabprm *tab1,
           const struct tabprm *tab2,
           int *equal)

{
  int status = 0;
  int i, M;

  if (tab1  == 0x0) return TABERR_NULL_POINTER;
  if (tab2  == 0x0) return TABERR_NULL_POINTER;
  if (equal == 0x0) return TABERR_NULL_POINTER;

  *equal = 0;

  if (tab1->M != tab2->M) {
    return 0;
  }

  M = tab1->M;

  if (!wcsutil_intEq(M, tab1->K, tab2->K) ||
      !wcsutil_intEq(M, tab1->map, tab2->map) ||
      !wcsutil_Eq(M, tab1->crval, tab2->crval)) {
    return 0;
  }

  for (i = 0; i < M; ++i) {
    if (tab1->index[i] == 0x0 && tab2->index[i] == 0x0) {
      /* Both NULL, therefore equal */
    } else if (tab1->index[i] == 0x0 || tab2->index[i] == 0x0) {
      return 0;
    } else {
      if (!wcsutil_Eq(tab1->K[i], tab1->index[i], tab2->index[i])) {
        return 0;
      }
    }
  }

  if (!wcsutil_Eq(tab1->nc * M, tab1->coord, tab2->coord)) {
    return 0;
  }

  *equal = 1;

  return 0;
}

@


4.22.1.3
log
@In tabcmp(), tabprm::nc may not be known if tabset() hasn't been invoked
on the tabprm.  Minor simplification in comparing tabprm::index[].
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.22.1.2 2014/05/10 14:31:52 mcalabre Exp mcalabre $
d421 1
a421 1
  int m, M, N;
d441 4
a444 3
  N = M;
  for (m = 0; m < M; m++) {
    if (!wcsutil_Eq(tab1->K[m], tab1->index[m], tab2->index[m])) {
d446 4
a450 2

    N *= tab1->K[m];
d453 1
a453 1
  if (!wcsutil_Eq(N, tab1->coord, tab2->coord)) {
@


4.21
log
@WCSLIB 4.21
@
text
@d3 1
a3 1
  WCSLIB 4.21 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.20.1.2 2014/03/21 06:32:19 mcalabre Exp mcalabre $
@


4.21.1.1
log
@WCSLIB 4.21 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.21 2014/03/24 05:12:27 mcalabre Exp $
@


4.20
log
@WCSLIB 4.20
@
text
@d3 2
a4 2
  WCSLIB 4.20 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2013, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 4.19.1.1 2013/09/29 14:20:38 mcalabre Exp mcalabre $
@


4.20.1.1
log
@WCSLIB 4.20 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.20 2013/12/18 05:42:49 mcalabre Exp $
@


4.20.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2014, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 4.20.1.1 2013/12/18 05:46:55 mcalabre Exp mcalabre $
@


4.19
log
@WCSLIB 4.19
@
text
@d3 1
a3 1
  WCSLIB 4.19 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.18.1.1 2013/07/13 10:02:37 mcalabre Exp mcalabre $
@


4.19.1.1
log
@WCSLIB 4.19 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.19 2013/09/29 14:17:51 mcalabre Exp $
@


4.18
log
@WCSLIB 4.18
@
text
@d3 1
a3 1
  WCSLIB 4.18 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.17.1.1 2013/01/29 05:32:32 cal103 Exp cal103 $
@


4.18.1.1
log
@WCSLIB 4.18 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.18 2013/07/13 10:00:04 mcalabre Exp $
@


4.17
log
@WCSLIB 4.17
@
text
@d3 1
a3 1
  WCSLIB 4.17 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.16.1.2 2013/01/29 05:09:44 cal103 Exp cal103 $
@


4.17.1.1
log
@WCSLIB 4.17 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.17 2013/01/29 05:29:20 cal103 Exp $
@


4.16
log
@WCSLIB 4.16
@
text
@d3 2
a4 2
  WCSLIB 4.16 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2012, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 4.15.1.1 2012/09/26 14:27:51 cal103 Exp cal103 $
@


4.16.1.1
log
@WCSLIB 4.16 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.16 2012/11/07 04:42:44 cal103 Exp $
@


4.16.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2013, Mark Calabretta
d25 1
a25 1
  $Id: tab.c,v 4.16.1.1 2012/11/07 04:45:56 cal103 Exp cal103 $
@


4.15
log
@WCSLIB 4.15
@
text
@d3 1
a3 1
  WCSLIB 4.15 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.14.1.1 2012/07/13 10:04:44 cal103 Exp cal103 $
@


4.15.1.1
log
@WCSLIB 4.15 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.15 2012/09/26 14:26:05 cal103 Exp $
@


4.14
log
@WCSLIB 4.14
@
text
@d3 1
a3 1
  WCSLIB 4.14 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: tab.c,v 4.13.1.3 2012/07/13 03:34:20 cal103 Exp cal103 $
@


4.14.1.1
log
@WCSLIB 4.14 development branch.
@
text
@d25 1
a25 1
  $Id: tab.c,v 4.14 2012/07/13 10:02:27 cal103 Exp $
@


4.13
log
@WCSLIB 4.13
@
text
@d3 1
a3 1
  WCSLIB 4.13 - an implementation of the FITS WCS standard.
d19 1
a19 1
  along with WCSLIB.  If not, see <http://www.gnu.org/licenses/>.
d21 5
a25 11
  Correspondence concerning WCSLIB may be directed to:
    Internet email: mcalabre@@atnf.csiro.au
    Postal address: Dr. Mark Calabretta
                    Australia Telescope National Facility, CSIRO
                    PO Box 76
                    Epping NSW 1710
                    AUSTRALIA

  Author: Mark Calabretta, Australia Telescope National Facility
  http://www.atnf.csiro.au/~mcalabre/index.html
  $Id: tab.c,v 4.12.1.2 2012/03/14 06:39:48 cal103 Exp cal103 $
d1141 2
d1308 1
a1308 1
  if (M > 1) free(tabcoord);
@


4.13.1.1
log
@WCSLIB 4.13 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.13 2012/03/14 07:39:30 cal103 Exp $
@


4.13.1.2
log
@Quenched a couple of nuisance compiler warnings.  Patch provided by
Michael Droettboom.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.13.1.1 2012/03/14 07:40:37 cal103 Exp cal103 $
a1146 2
  tabcoord = 0x0;
  nv = 0;
d1312 1
a1312 1
  if (tabcoord) free(tabcoord);
@


4.13.1.3
log
@Changed contact details.
@
text
@d19 1
a19 1
  along with WCSLIB.  If not, see http://www.gnu.org/licenses.
d21 11
a31 5
  Direct correspondence concerning WCSLIB to mark@@calabretta.id.au

  Author: Mark Calabretta, Australia Telescope National Facility, CSIRO.
  http://www.atnf.csiro.au/people/Mark.Calabretta
  $Id: tab.c,v 4.13.1.2 2012/07/12 15:34:49 cal103 Exp cal103 $
@


4.12
log
@WCSLIB 4.12
@
text
@d3 1
a3 1
  WCSLIB 4.12 - an implementation of the FITS WCS standard.
d31 1
a31 1
  $Id: tab.c,v 4.11.1.1 2012/02/20 23:31:13 cal103 Exp cal103 $
d480 4
a483 2
  if (tab->err) free(tab->err);
  tab->err = 0x0;
@


4.12.1.1
log
@WCSLIB 4.12 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.12 2012/02/29 07:57:56 cal103 Exp $
@


4.12.1.2
log
@Minor tweak to tabfree().
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.12.1.1 2012/02/29 07:59:10 cal103 Exp cal103 $
d480 2
a481 4
  if (tab->err) {
    free(tab->err);
    tab->err = 0x0;
  }
@


4.11
log
@WCSLIB 4.11
@
text
@d3 1
a3 1
  WCSLIB 4.11 - an implementation of the FITS WCS standard.
d31 1
a31 1
  $Id: tab.c,v 4.10.1.1 2012/02/05 23:42:46 cal103 Exp cal103 $
@


4.11.1.1
log
@WCSLIB 4.11 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.11 2012/02/20 23:30:02 cal103 Exp $
@


4.10
log
@WCSLIB 4.10
@
text
@d3 1
a3 1
  WCSLIB 4.10 - an implementation of the FITS WCS standard.
d31 1
a31 1
  $Id: tab.c,v 4.9.1.1 2012/01/24 05:41:45 cal103 Exp cal103 $
@


4.10.1.1
log
@WCSLIB 4.10 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.10 2012/02/05 23:41:44 cal103 Exp $
@


4.9
log
@WCSLIB 4.9
@
text
@d3 1
a3 1
  WCSLIB 4.9 - an implementation of the FITS WCS standard.
d31 1
a31 1
  $Id: tab.c,v 4.8.1.3 2012/01/24 05:23:06 cal103 Exp cal103 $
@


4.9.1.1
log
@WCSLIB 4.9 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.9 2012/01/24 05:40:29 cal103 Exp $
@


4.8
log
@WCSLIB 4.8
@
text
@d3 2
a4 2
  WCSLIB 4.8 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2011, Mark Calabretta
d31 1
a31 1
  $Id: tab.c,v 4.7.1.5 2011/08/12 05:42:29 cal103 Exp cal103 $
d621 1
a621 1
    wcserr_prt(tab->err, "");
@


4.8.1.1
log
@WCSLIB 4.8 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.8 2011/08/15 08:05:53 cal103 Exp $
@


4.8.1.2
log
@Minor refinement in tabprt() for printing tabprm::err.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.8.1.1 2011/08/15 08:07:06 cal103 Exp cal103 $
d621 1
a621 1
    wcserr_prt(tab->err, "             ");
@


4.8.1.3
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2012, Mark Calabretta
d31 1
a31 1
  $Id: tab.c,v 4.8.1.2 2011/11/17 03:09:49 cal103 Exp cal103 $
@


4.7
log
@WCSLIB 4.7
@
text
@d3 1
a3 1
  WCSLIB 4.7 - an implementation of the FITS WCS standard.
d31 1
a31 1
  $Id: tab.c,v 4.6.1.8 2011/02/07 04:28:45 cal103 Exp cal103 $
d39 1
d55 3
d63 2
d67 10
a77 1
  if (tab == 0x0) return 1;
d80 2
a81 1
    return 3;
d90 3
a92 1
        return 3;
d155 1
a155 1
          return 2;
d171 1
a171 1
          return 2;
d187 1
a187 1
          return 2;
d203 1
a203 1
          return 2;
d212 1
a212 1
           return 2;
d220 1
a220 1
                return 2;
d237 1
a237 1
          return 2;
d281 2
d284 1
d286 2
a287 1
  if (tab == 0x0) return 1;
d291 2
a292 1
    return 2;
d299 3
a301 1
      return 3;
d312 2
a313 1
    return 2;
d320 2
a321 1
    return 2;
d372 2
d376 1
d378 3
a380 1
  if (tabsrc == 0x0) return 1;
d384 2
a385 1
    return 2;
d424 1
a424 1
  if (tab == 0x0) return 1;
d480 3
d497 1
a497 1
  if (tab == 0x0) return 1;
d508 1
a508 1
  wcsprintf("          K: %p\n", (void *)tab->K);
d516 1
a516 1
  wcsprintf("        map: %p\n", (void *)tab->map);
d524 1
a524 1
  wcsprintf("      crval: %p\n", (void *)tab->crval);
d532 1
a532 1
  wcsprintf("      index: %p\n", (void *)tab->index);
d534 2
a535 1
    wcsprintf("   index[%d]: %p", m, (void *)tab->index[m]);
d548 1
a548 1
  wcsprintf("      coord: %p\n", (void *)tab->coord);
d570 2
a571 4
  if (tab->sense == 0x0) {
    wcsprintf("      sense: (nil)\n");
  } else {
    wcsprintf("      sense: %p\n", (void *)tab->sense);
d579 2
a580 4
  if (tab->p0 == 0x0) {
    wcsprintf("         p0: (nil)\n");
  } else {
    wcsprintf("         p0: %p\n", (void *)tab->p0);
d588 2
a589 4
  if (tab->delta == 0x0) {
    wcsprintf("      delta: (nil)\n");
  } else {
    wcsprintf("      delta: %p\n", (void *)tab->delta);
d597 1
a597 1
  wcsprintf("    extrema: %p\n", (void *)tab->extrema);
d619 5
d629 1
a629 1
  wcsprintf("        m_K: %p", (void *)tab->m_K);
d633 1
a633 1
  wcsprintf("      m_map: %p", (void *)tab->m_map);
d637 1
a637 1
  wcsprintf("    m_crval: %p", (void *)tab->m_crval);
d641 1
a641 1
  wcsprintf("    m_index: %p", (void *)tab->m_index);
d645 2
a646 1
    wcsprintf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]);
d651 1
a651 1
  wcsprintf("    m_coord: %p", (void *)tab->m_coord);
d663 2
d667 1
d669 2
a670 1
  if (tab == 0x0) return 1;
d674 2
a675 1
    return 3;
d680 2
a681 1
    return 2;
d687 3
a689 1
      return 3;
d698 2
a699 1
    return 2;
d705 3
a707 1
      return 3;
d713 2
a714 1
    return 2;
d741 1
a741 1
      return 2;
d746 1
a746 1
      return 2;
d752 1
a752 1
      return 2;
d760 1
a760 1
      return 2;
d796 3
a798 1
              return 3;
d809 3
a811 1
              return 3;
d823 2
a824 1
        return 3;
d901 2
d908 4
a913 1
  if (tab == 0x0) return 1;
d949 1
a949 1
            status = 4;
d965 1
a965 1
                status = 4;
d977 1
a977 1
                status = 4;
d1005 1
a1005 1
                status = 4;
d1017 1
a1017 1
                status = 4;
d1043 1
a1043 1
        status = 4;
d1121 2
d1132 4
a1137 1
  if (tab == 0x0) return 1;
d1261 1
a1261 1
      status = 5;
d1272 1
a1272 1
          status = 5;
d1350 1
a1350 1
* centred on, integral pixel coordinates in FITS. 
d1450 2
a1451 2
* coordinates in FITS. 
*  
d1462 1
a1462 1
int tabvox( 
d1583 1
a1583 1
  /* No solution in this sub-)voxel. */
@


4.7.1.1
log
@WCSLIB 4.7 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.7 2011/02/07 07:03:42 cal103 Exp $
@


4.7.1.2
log
@Added error messaging based on wcserr.  Changes supplied by Michael
Droettboom (STScI) with respect to the released WCSLIB 4.7 sources.
@
text
@d62 1
a62 1
  if (tab == 0x0) return TABERR_NULL_POINTER;
a63 2
  wcserr_ini(&tab->err);
  
d65 1
a65 3
    return WCSERR_SET(
      &tab->err, TABERR_MEMORY,
      "M must be positive, got %d", M);         
d74 1
a74 4
        return WCSERR_SET(
          &tab->err, TABERR_BAD_PARAMS,
          "Invalid tabular parameters: Each element of K must be non-negative, got %d",
          K[m]);         
d137 1
a137 1
          return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d153 1
a153 1
          return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d169 1
a169 1
          return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d185 1
a185 1
          return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d194 1
a194 1
          return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d202 1
a202 2
                return WCSERR_SET(
                  &tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d219 1
a219 1
          return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d269 1
a269 1
    return WCSERR_SET(&tab->err, TABERR_MEMORY, "Null pointers in tabprm struct");
d276 1
a276 3
      return WCSERR_SET(
        &tab->err, TABERR_BAD_PARAMS,
        "Invalid tabular parameters: Each element of K must be non-negative, got %d", M);         
d287 1
a287 1
    return WCSERR_SET(&tab->err, TABERR_MEMORY, "tabprm struct inconsistent");
d294 1
a294 1
    return WCSERR_SET(&tab->err, TABERR_MEMORY, "tabprm struct inconsistent");
d348 1
a348 1
  if (tabsrc == 0x0) return TABERR_NULL_POINTER;
d352 1
a352 3
    return WCSERR_SET(
      &tabdst->err, TABERR_MEMORY,
      "M must be positive, got %d", M);         
d391 1
a391 1
  if (tab == 0x0) return TABERR_NULL_POINTER;
d461 1
a461 1
  if (tab == 0x0) return TABERR_NULL_POINTER;
d629 1
a629 1
  if (tab == 0x0) return TABERR_NULL_POINTER;
d633 1
a633 3
    return WCSERR_SET(
      &tab->err, TABERR_BAD_PARAMS,
      "Invalid tabular parameters: M must be positive, got %d", M);         
d638 1
a638 1
    return WCSERR_SET(&tab->err, TABERR_MEMORY, "Null pointers in tabprm struct");
d644 1
a644 4
      return WCSERR_SET(
        &tab->err, TABERR_BAD_PARAMS,
        "Invalid tabular parameters: Each element of K must be positive, got %d",
        tab->K[m]);         
d653 1
a653 1
    return WCSERR_SET(&tab->err, TABERR_MEMORY, "Null pointers in tabprm struct");
d659 1
a659 4
      return WCSERR_SET(
        &tab->err, TABERR_BAD_PARAMS,
        "Invalid tabular parameters: Each element of map must be non-negative, got %d",
        i);         
d665 1
a665 1
    return WCSERR_SET(&tab->err, TABERR_MEMORY, "Null pointers in tabprm struct");
d692 1
a692 1
      return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d697 1
a697 1
      return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d703 1
a703 1
      return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d711 1
a711 1
      return WCSERR_SET(&tab->err, TABERR_MEMORY, tab_errmsg[TABERR_MEMORY]);
d747 1
a747 3
              return WCSERR_SET(
                &tab->err, TABERR_BAD_PARAMS,
                "Invalid tabular parameters: Index vectors are not monotonically increasing");
d758 1
a758 3
              return WCSERR_SET(
                &tab->err, TABERR_BAD_PARAMS,
                "Invalid tabular parameters: Index vectors are not monotonically decreasing");
d770 1
a770 3
        return WCSERR_SET(
          &tab->err, TABERR_BAD_PARAMS,
          "Invalid tabular parameters: Index vectors are not monotonic");
d854 1
a854 1
  if (tab == 0x0) return TABERR_NULL_POINTER;
d890 1
a890 1
            status = TABERR_BAD_X;
d906 1
a906 1
                status = TABERR_BAD_X;
d918 1
a918 1
                status = TABERR_BAD_X;
d946 1
a946 1
                status = TABERR_BAD_X;
d958 1
a958 1
                status = TABERR_BAD_X;
d984 1
a984 1
        status = TABERR_BAD_X;
a1047 3
  if (status == TABERR_BAD_X) {
    WCSERR_SET(&tab->err, status, tab_errmsg[status]);
  }
d1073 1
a1073 1
  if (tab == 0x0) return TABERR_NULL_POINTER;
d1197 1
a1197 1
      status = TABERR_BAD_WORLD;
d1208 1
a1208 1
          status = TABERR_BAD_WORLD;
a1247 3
  if (status == TABERR_BAD_WORLD) {
    WCSERR_SET(&tab->err, TABERR_BAD_WORLD, tab_errmsg[TABERR_BAD_WORLD]);
  }
@


4.7.1.3
log
@Revised implementation of Michael Droettboom's error messaging system.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.7.1.1 2011/02/07 07:04:22 cal103 Exp cal103 $
a38 1
#include "wcserr.h"
a53 3
/* Convenience macro for invoking wcserr_set(). */
#define TAB_ERRMSG(status) WCSERR_SET(status), tab_errmsg[status]

a58 2
  static const char *function = "tabini";

a60 1
  struct wcserr **err;
d64 2
a65 8
  /* Initialize error message handling. */
  err = &(tab->err);
  if (tab->err && tab->flag != -1) {
    free(tab->err);
  }
  tab->err = 0x0;


d67 3
a69 2
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "M must be positive, got %d", M);
d78 4
a81 3
        return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
          "Invalid tabular parameters: Each element of K must be "
          "non-negative, got %d", K[m]);
d144 1
a144 1
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d160 1
a160 1
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d176 1
a176 1
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d192 1
a192 1
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d201 1
a201 1
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d209 2
a210 1
                return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d227 1
a227 1
          return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
a270 2
  static const char *function = "tabmem";

a271 1
  struct wcserr **err;
d273 1
a273 2
  if (tab == 0x0) return TABERR_NULL_POINTER;
  err = &(tab->err);
d277 1
a277 2
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
d284 3
a286 3
      return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
        "Invalid tabular parameters: Each element of K must be "
        "non-negative, got %d", M);
d297 1
a297 2
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "tabprm struct inconsistent");
d304 1
a304 2
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "tabprm struct inconsistent");
a354 2
  static const char *function = "tabcpy";

a356 1
  struct wcserr **err;
a358 2
  if (tabdst == 0x0) return TABERR_NULL_POINTER;
  err = &(tabdst->err);
d362 3
a364 2
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "M must be positive, got %d", M);
a458 3
  if (tab->err) free(tab->err);
  tab->err = 0x0;

a599 5
  wcsprintf("        err: %p\n", (void *)tab->err);
  if (tab->err) {
    wcserr_prt(tab->err, "");
  }

a637 2
  static const char *function = "tabset";

a639 1
  struct wcserr **err;
a641 1
  err = &(tab->err);
d645 3
a647 2
    return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
      "Invalid tabular parameters: M must be positive, got %d", M);
d652 1
a652 2
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
d658 4
a661 3
      return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
        "Invalid tabular parameters: Each element of K must be positive, "
        "got %d", tab->K[m]);
d670 1
a670 2
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
d676 4
a679 3
      return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
        "Invalid tabular parameters: Each element of map must be "
        "non-negative, got %d", i);
d685 1
a685 2
    return wcserr_set(WCSERR_SET(TABERR_MEMORY),
      "Null pointers in tabprm struct");
d712 1
a712 1
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d717 1
a717 1
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d723 1
a723 1
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d731 1
a731 1
      return wcserr_set(TAB_ERRMSG(TABERR_MEMORY));
d767 3
a769 3
              return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
                "Invalid tabular parameters: Index vectors are not "
                "monotonically increasing");
d780 3
a782 3
              return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
                "Invalid tabular parameters: Index vectors are not "
                "monotonically decreasing");
d794 2
a795 1
        return wcserr_set(WCSERR_SET(TABERR_BAD_PARAMS),
a872 2
  static const char *function = "tabx2s";

a877 1
  struct wcserr **err;
d879 1
a880 3
  err = &(tab->err);

  /* Initialize if required. */
d916 1
a916 1
            status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
d932 1
a932 1
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
d944 1
a944 1
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
d972 1
a972 1
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
d984 1
a984 1
                status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
d1010 1
a1010 1
        status = wcserr_set(TAB_ERRMSG(TABERR_BAD_X));
d1074 3
a1090 2
  static const char *function = "tabs2x";

a1099 1
  struct wcserr **err;
d1101 1
a1102 3
  err = &(tab->err);

  /* Initialize if required. */
d1226 1
a1226 1
      status = wcserr_set(TAB_ERRMSG(TABERR_BAD_WORLD));
d1237 1
a1237 1
          status = wcserr_set(TAB_ERRMSG(TABERR_BAD_WORLD));
d1277 3
d1318 1
a1318 1
* centred on, integral pixel coordinates in FITS.
d1418 2
a1419 2
* coordinates in FITS.
*
d1430 1
a1430 1
int tabvox(
@


4.7.1.4
log
@Fixed typo in comment.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.7.1.3 2011/08/09 02:43:50 cal103 Exp cal103 $
d1587 1
a1587 1
  /* No solution in this sub-voxel. */
@


4.7.1.5
log
@Use the WCSPRINTF_PTR() macro for printing addresses.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.7.1.4 2011/08/10 04:49:56 cal103 Exp cal103 $
d508 1
a508 1
  WCSPRINTF_PTR("          K: ", tab->K, "\n");
d516 1
a516 1
  WCSPRINTF_PTR("        map: ", tab->map, "\n");
d524 1
a524 1
  WCSPRINTF_PTR("      crval: ", tab->crval, "\n");
d532 1
a532 1
  WCSPRINTF_PTR("      index: ", tab->index, "\n");
d534 1
a534 2
    wcsprintf("   index[%d]: ", m);
    WCSPRINTF_PTR("", tab->index[m], "");
d547 1
a547 1
  WCSPRINTF_PTR("      coord: ", tab->coord, "\n");
d569 4
a572 2
  WCSPRINTF_PTR("      sense: ", tab->sense, "\n");
  if (tab->sense) {
d580 4
a583 2
  WCSPRINTF_PTR("         p0: ", tab->p0, "\n");
  if (tab->p0) {
d591 4
a594 2
  WCSPRINTF_PTR("      delta: ", tab->delta, "\n");
  if (tab->delta) {
d602 1
a602 1
  WCSPRINTF_PTR("    extrema: ", tab->extrema, "\n");
d624 1
a624 1
  WCSPRINTF_PTR("        err: ", tab->err, "\n");
d634 1
a634 1
  WCSPRINTF_PTR("        m_K: ", tab->m_K, "");
d638 1
a638 1
  WCSPRINTF_PTR("      m_map: ", tab->m_map, "");
d642 1
a642 1
  WCSPRINTF_PTR("    m_crval: ", tab->m_crval, "");
d646 1
a646 1
  WCSPRINTF_PTR("    m_index: ", tab->m_index, "");
d650 1
a650 2
    wcsprintf(" m_indxs[%d]: ", m);
    WCSPRINTF_PTR("", tab->m_indxs[m], "");
d655 1
a655 1
  WCSPRINTF_PTR("    m_coord: ", tab->m_coord, "");
@


4.6
log
@WCSLIB 4.6
@
text
@d3 2
a4 2
  WCSLIB 4.6 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2010, Mark Calabretta
d31 1
a31 1
  $Id: tab.c,v 4.5.1.1 2010/07/16 07:05:31 cal103 Exp cal103 $
d40 1
d464 1
a464 1
    printf("The tabprm struct is UNINITIALIZED.\n");
d468 2
a469 2
  printf("       flag: %d\n", tab->flag);
  printf("          M: %d\n", tab->M);
d472 2
a473 2
  printf("          K: %p\n", (void *)tab->K);
  printf("            ");
d475 1
a475 1
    printf("%6d", tab->K[m]);
d477 1
a477 1
  printf("\n");
d480 2
a481 2
  printf("        map: %p\n", (void *)tab->map);
  printf("            ");
d483 1
a483 1
    printf("%6d", tab->map[m]);
d485 1
a485 1
  printf("\n");
d488 2
a489 2
  printf("      crval: %p\n", (void *)tab->crval);
  printf("            ");
d491 1
a491 1
    printf("  %- 11.5g", tab->crval[m]);
d493 1
a493 1
  printf("\n");
d496 1
a496 1
  printf("      index: %p\n", (void *)tab->index);
d498 1
a498 1
    printf("   index[%d]: %p", m, (void *)tab->index[m]);
d502 1
a502 1
          printf("\n            ");
d504 1
a504 1
        printf("  %- 11.5g", tab->index[m][k]);
d506 1
a506 1
      printf("\n");
d511 1
a511 1
  printf("      coord: %p\n", (void *)tab->coord);
d524 1
a524 1
    printf("             (*%s)", text);
d526 1
a526 1
      printf("  %- 11.5g", *(dp++));
d528 1
a528 1
    printf("\n");
d531 1
a531 1
  printf("         nc: %d\n", tab->nc);
d534 1
a534 1
    printf("      sense: (nil)\n");
d536 2
a537 2
    printf("      sense: %p\n", (void *)tab->sense);
    printf("            ");
d539 1
a539 1
      printf("%6d", tab->sense[m]);
d541 1
a541 1
    printf("\n");
d545 1
a545 1
    printf("         p0: (nil)\n");
d547 2
a548 2
    printf("         p0: %p\n", (void *)tab->p0);
    printf("            ");
d550 1
a550 1
      printf("%6d", tab->p0[m]);
d552 1
a552 1
    printf("\n");
d556 1
a556 1
    printf("      delta: (nil)\n");
d558 2
a559 2
    printf("      delta: %p\n", (void *)tab->delta);
    printf("            ");
d561 1
a561 1
      printf("  %- 11.5g", tab->delta[m]);
d563 1
a563 1
    printf("\n");
d566 1
a566 1
  printf("    extrema: %p\n", (void *)tab->extrema);
d580 1
a580 1
    printf("             (*,*%s)", text);
d582 2
a583 2
      if (m == tab->M) printf("->  ");
      printf("  %- 11.5g", *(dp++));
d585 1
a585 1
    printf("\n");
d589 19
a607 19
  printf("     m_flag: %d\n", tab->m_flag);
  printf("        m_M: %d\n", tab->m_M);
  printf("        m_N: %d\n", tab->m_N);

  printf("        m_K: %p", (void *)tab->m_K);
  if (tab->m_K == tab->K) printf("  (= K)");
  printf("\n");

  printf("      m_map: %p", (void *)tab->m_map);
  if (tab->m_map == tab->map) printf("  (= map)");
  printf("\n");

  printf("    m_crval: %p", (void *)tab->m_crval);
  if (tab->m_crval == tab->crval) printf("  (= crval)");
  printf("\n");

  printf("    m_index: %p", (void *)tab->m_index);
  if (tab->m_index == tab->index) printf("  (= index)");
  printf("\n");
d609 3
a611 3
    printf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]);
    if (tab->m_indxs[m] == tab->index[m]) printf("  (= index[%d])", m);
    printf("\n");
d614 3
a616 3
  printf("    m_coord: %p", (void *)tab->m_coord);
  if (tab->m_coord == tab->coord) printf("  (= coord)");
  printf("\n");
d627 1
a627 1
  double *dcrd, *dmax, *dmin, *Psi;
d723 1
a723 1
      if ((Psi = tab->index[m]) == 0) {
d775 1
a775 1
  /* Deduce the extremal values of the coordinate elements in each row. */
d781 18
a798 1
      *(dmax+m) = *(dmin+m) = *dcrd;
d801 2
a802 1
    for (i = 1; i < tab->K[0]; i++) {
d806 18
d847 1
a847 1
  int i, iv, k, *Km, m, M, n, nv, offset, p0, status;
d870 1
d874 2
a875 1
      if ((Psi = tab->index[m]) == 0) {
d880 4
d886 1
a886 1
          if (Psi[0]-0.5 <= psi_m && psi_m <= Psi[0]+0.5) {
d898 2
a899 2
            if (psi_m < Psi[0]) {
              if (Psi[0] - 0.5*(Psi[1]-Psi[0]) <= psi_m) {
d901 1
a901 1
                k = 0;
d910 2
a911 2
            } else if (Psi[*Km-1] < psi_m) {
              if (psi_m <= Psi[*Km-1] + 0.5*(Psi[*Km-1]-Psi[*Km-2])) {
d913 1
a913 1
                k = *Km - 2;
d923 1
a923 1
              for (k = 0; k < *Km-1; k++) {
d938 2
a939 2
            if (psi_m > Psi[0]) {
              if (Psi[0] + 0.5*(Psi[0]-Psi[1]) >= psi_m) {
d941 1
a941 1
                k = 0;
d950 2
a951 2
            } else if (psi_m < Psi[*Km-1]) {
              if (Psi[*Km-1] - 0.5*(Psi[*Km-2]-Psi[*Km-1]) <= psi_m) {
d953 1
a953 1
                k = *Km - 2;
d963 1
a963 1
              for (k = 0; k < *Km-1; k++) {
d981 1
a981 1
      if (upsilon < -0.5 || upsilon > *Km - 0.5) {
d988 12
a999 11
      /* Fiducial array indices and fractional offset. */
      p0 = (int)floor(upsilon);
      tab->p0[m] = p0;
      tab->delta[m] = upsilon - p0;

      if (p0 == -1) {
       tab->p0[m] += 1;
       tab->delta[m] -= 1.0;
      } else if (p0 == *Km-1 && *Km > 1) {
       tab->p0[m] -= 1;
       tab->delta[m] += 1.0;
d1064 1
a1064 1
  int tabvox(struct tabprm *, const double *, int, unsigned int *);
d1066 2
a1067 2
  int edge, i, ic, k, *Km, M, m, n, status;
  double *Psi, psi_m, upsilon;
d1081 5
d1103 1
a1103 1
          ic += tab->K[0] - 1;
d1106 3
d1114 1
a1114 1
        /* Deal with the one-dimensional case separately. */
d1123 1
a1123 1
               (tab->index[0] == 0 ||
d1133 17
a1149 4
        /* Multi-dimensional tables are much harder. */
        if (!edge && tabvox(tab, wp, 0, 0) == 0) {
          /* Found a solution. */
          break;
d1160 35
d1202 4
a1205 2
        upsilon = tab->p0[m] + tab->delta[m];
        if (upsilon < -0.5 || upsilon > *Km - 0.5) {
d1212 2
a1213 1
          if ((Psi = tab->index[m]) == 0) {
d1218 4
d1224 1
a1224 1
              psi_m = Psi[0];
d1226 1
a1226 1
              k = (int)upsilon;
d1228 1
a1228 1
              if (k < *Km-1) {
d1246 2
d1251 3
a1253 1
/*--------------------------------------------------------------------------*/
d1255 1
a1255 3
int tabedge(tab)

struct tabprm* tab;
d1264 2
d1269 1
a1269 1
      /* Edge effects? */
d1277 28
a1304 3
/*--------------------------------------------------------------------------*/

int tabrow(tab, wp)
d1306 1
a1306 2
struct tabprm* tab;
const double *wp;
d1310 2
a1311 2
  unsigned int eq, et, gt, lt;
  const double tol = 1.0e-10;
d1316 6
a1321 1
  /* Could the coordinate lie somewhere along this row of voxels? */
a1323 2
  eq = 0;
  nv = 1 << M;
d1325 1
a1325 1
    /* Find the extrema at this end of the row. */
d1330 2
d1337 1
a1338 2
    offset += tab->p0[0];
    if (iv & 1 && tab->K[0] > 1) offset++;
d1340 13
a1352 2
    et = 0;
    cp = tab->extrema + offset*M;
d1354 1
d1356 2
d1359 1
a1359 1
        et |= (1 << m);
d1367 3
a1369 2
    if (et == nv-1) {
      /* Solution found in a corner. */
a1371 7

    eq |= et;
  }

  if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
    /* A solution could lie within this row of voxels. */
    return 0;
d1378 19
a1396 1
/*--------------------------------------------------------------------------*/
d1398 6
a1403 6
int tabvox(tab, wp, level, vox)

struct tabprm* tab;
const double *wp;
int level;
unsigned int *vox;
d1406 1
a1406 1
  int i, iv, jv, M, m, nv, offset;
d1408 1
a1408 1
  const double tol = 1.0e-10;
d1413 3
d1421 3
a1423 1
  /* Could the coordinate lie within this voxel? */
a1426 1
  nv = 1 << M;
d1428 1
a1428 1
    /* Compute the coordinates of this corner of the voxel. */
d1432 1
d1438 3
d1442 1
a1442 1
      offset = 0;
d1444 1
a1444 3
      for (m = M-1; m >= 0; m--) {
        offset *= tab->K[m];
        offset += tab->p0[m];
a1445 1
          if (tab->K[m] > 1) offset++;
d1454 2
a1455 1
      cp = tab->coord + offset*M;
d1466 1
d1468 2
d1480 1
a1480 1
      /* Solution found in a corner. */
d1487 1
d1489 1
a1489 1
    /* The coordinate could lie within this voxel, but does it? */
d1491 1
d1493 1
a1493 1
      /* Stop the recursion. */
d1502 1
a1502 1
    /* Subdivide and try again. */
d1504 1
d1512 2
a1513 1
      if (tabvox(tab, wp, level+1, vox2) == 0) {
d1519 1
a1519 1
  /* No solution in this voxel. */
@


4.6.1.1
log
@WCSLIB 4.6 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.6 2010/11/16 06:15:31 cal103 Exp $
@


4.6.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2011, Mark Calabretta
d31 1
a31 1
  $Id: tab.c,v 4.6.1.1 2010/11/16 06:16:19 cal103 Exp cal103 $
@


4.6.1.3
log
@Replaced calls to printf() with wcsprintf().
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.6.1.2 2011/01/14 06:33:16 cal103 Exp cal103 $
a39 1
#include "wcsprintf.h"
d463 1
a463 1
    wcsprintf("The tabprm struct is UNINITIALIZED.\n");
d467 2
a468 2
  wcsprintf("       flag: %d\n", tab->flag);
  wcsprintf("          M: %d\n", tab->M);
d471 2
a472 2
  wcsprintf("          K: %p\n", (void *)tab->K);
  wcsprintf("            ");
d474 1
a474 1
    wcsprintf("%6d", tab->K[m]);
d476 1
a476 1
  wcsprintf("\n");
d479 2
a480 2
  wcsprintf("        map: %p\n", (void *)tab->map);
  wcsprintf("            ");
d482 1
a482 1
    wcsprintf("%6d", tab->map[m]);
d484 1
a484 1
  wcsprintf("\n");
d487 2
a488 2
  wcsprintf("      crval: %p\n", (void *)tab->crval);
  wcsprintf("            ");
d490 1
a490 1
    wcsprintf("  %- 11.5g", tab->crval[m]);
d492 1
a492 1
  wcsprintf("\n");
d495 1
a495 1
  wcsprintf("      index: %p\n", (void *)tab->index);
d497 1
a497 1
    wcsprintf("   index[%d]: %p", m, (void *)tab->index[m]);
d501 1
a501 1
          wcsprintf("\n            ");
d503 1
a503 1
        wcsprintf("  %- 11.5g", tab->index[m][k]);
d505 1
a505 1
      wcsprintf("\n");
d510 1
a510 1
  wcsprintf("      coord: %p\n", (void *)tab->coord);
d523 1
a523 1
    wcsprintf("             (*%s)", text);
d525 1
a525 1
      wcsprintf("  %- 11.5g", *(dp++));
d527 1
a527 1
    wcsprintf("\n");
d530 1
a530 1
  wcsprintf("         nc: %d\n", tab->nc);
d533 1
a533 1
    wcsprintf("      sense: (nil)\n");
d535 2
a536 2
    wcsprintf("      sense: %p\n", (void *)tab->sense);
    wcsprintf("            ");
d538 1
a538 1
      wcsprintf("%6d", tab->sense[m]);
d540 1
a540 1
    wcsprintf("\n");
d544 1
a544 1
    wcsprintf("         p0: (nil)\n");
d546 2
a547 2
    wcsprintf("         p0: %p\n", (void *)tab->p0);
    wcsprintf("            ");
d549 1
a549 1
      wcsprintf("%6d", tab->p0[m]);
d551 1
a551 1
    wcsprintf("\n");
d555 1
a555 1
    wcsprintf("      delta: (nil)\n");
d557 2
a558 2
    wcsprintf("      delta: %p\n", (void *)tab->delta);
    wcsprintf("            ");
d560 1
a560 1
      wcsprintf("  %- 11.5g", tab->delta[m]);
d562 1
a562 1
    wcsprintf("\n");
d565 1
a565 1
  wcsprintf("    extrema: %p\n", (void *)tab->extrema);
d579 1
a579 1
    wcsprintf("             (*,*%s)", text);
d581 2
a582 2
      if (m == tab->M) wcsprintf("->  ");
      wcsprintf("  %- 11.5g", *(dp++));
d584 1
a584 1
    wcsprintf("\n");
d588 19
a606 19
  wcsprintf("     m_flag: %d\n", tab->m_flag);
  wcsprintf("        m_M: %d\n", tab->m_M);
  wcsprintf("        m_N: %d\n", tab->m_N);

  wcsprintf("        m_K: %p", (void *)tab->m_K);
  if (tab->m_K == tab->K) wcsprintf("  (= K)");
  wcsprintf("\n");

  wcsprintf("      m_map: %p", (void *)tab->m_map);
  if (tab->m_map == tab->map) wcsprintf("  (= map)");
  wcsprintf("\n");

  wcsprintf("    m_crval: %p", (void *)tab->m_crval);
  if (tab->m_crval == tab->crval) wcsprintf("  (= crval)");
  wcsprintf("\n");

  wcsprintf("    m_index: %p", (void *)tab->m_index);
  if (tab->m_index == tab->index) wcsprintf("  (= index)");
  wcsprintf("\n");
d608 3
a610 3
    wcsprintf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]);
    if (tab->m_indxs[m] == tab->index[m]) wcsprintf("  (= index[%d])", m);
    wcsprintf("\n");
d613 3
a615 3
  wcsprintf("    m_coord: %p", (void *)tab->m_coord);
  if (tab->m_coord == tab->coord) wcsprintf("  (= coord)");
  wcsprintf("\n");
@


4.6.1.4
log
@Bug fixes in tabx2s() and tabs2x() for default indexes.  Switched
psi_m and upsilon to 1-relative indexes to maintain similarity with
the equations in Paper III, hopefully making the code easier to
follow.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.6.1.3 2011/01/25 00:35:11 cal103 Exp cal103 $
d775 1
a775 1
  /* Find the extremal values of the coordinate elements in each row. */
d811 1
a811 1
  int i, iv, k, *Km, m, M, n, nv, offset, p1, status;
a833 1
      /* N.B. psi_m and Upsilon_m are 1-relative FITS indexes. */
d837 1
a837 2
      Psi = tab->index[m];
      if (Psi == 0x0) {
a841 4
        /* To ease confusion, decrement Psi so that we can use 1-relative
           C array indexing to match the 1-relative FITS indexing. */
        Psi--;

d844 1
a844 1
          if (Psi[1]-0.5 <= psi_m && psi_m <= Psi[1]+0.5) {
d856 2
a857 2
            if (psi_m < Psi[1]) {
              if (Psi[1] - 0.5*(Psi[2]-Psi[1]) <= psi_m) {
d859 1
a859 1
                k = 1;
d868 2
a869 2
            } else if (Psi[*Km] < psi_m) {
              if (psi_m <= Psi[*Km] + 0.5*(Psi[*Km]-Psi[*Km-1])) {
d871 1
a871 1
                k = *Km - 1;
d881 1
a881 1
              for (k = 1; k < *Km; k++) {
d896 2
a897 2
            if (psi_m > Psi[1]) {
              if (Psi[1] + 0.5*(Psi[1]-Psi[2]) >= psi_m) {
d899 1
a899 1
                k = 1;
d908 2
a909 2
            } else if (psi_m < Psi[*Km]) {
              if (Psi[*Km] - 0.5*(Psi[*Km-1]-Psi[*Km]) <= psi_m) {
d911 1
a911 1
                k = *Km - 1;
d921 1
a921 1
              for (k = 1; k < *Km; k++) {
d939 1
a939 1
      if (upsilon < 0.5 || upsilon > *Km + 0.5) {
d946 11
a956 12
      /* Fiducial array indices and fractional offset.
         p1 is 1-relative while tab::p0 is 0-relative. */
      p1 = (int)floor(upsilon);
      tab->p0[m] = p1 - 1;
      tab->delta[m] = upsilon - p1;

      if (p1 == 0) {
        tab->p0[m] += 1;
        tab->delta[m] -= 1.0;
      } else if (p1 == *Km && *Km > 1) {
        tab->p0[m] -= 1;
        tab->delta[m] += 1.0;
d1055 1
a1055 1
          ic += tab->K[0];
a1057 3

          /* Because ic will be incremented when the loop is reentered. */
          ic--;
d1072 1
a1072 1
               (tab->index[0] == 0x0 ||
d1103 2
a1104 4
        /* N.B. Upsilon_m and psi_m are 1-relative FITS indexes. */
        upsilon = (tab->p0[m] + 1) + tab->delta[m];

        if (upsilon < 0.5 || upsilon > *Km + 0.5) {
d1111 1
a1111 2
          Psi = tab->index[m];
          if (Psi == 0x0) {
a1115 4
            /* Decrement Psi and use 1-relative C array indexing to match the
               1-relative FITS indexing. */
            Psi--;

d1118 1
a1118 1
              psi_m = Psi[1];
d1120 1
a1120 1
              k = (int)(upsilon);
d1122 1
a1122 1
              if (k < *Km) {
d1177 1
a1177 1
  const double tol = 1e-10;
d1244 1
a1244 1
  const double tol = 1e-10;
@


4.6.1.5
log
@Commented the code for tabedge(), tabrow(), and tabvox(), also with
some minor efficiencies in tabrow().
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.6.1.4 2011/02/01 05:38:50 cal103 Exp cal103 $
d723 1
a723 1
      if ((Psi = tab->index[m]) == 0x0) {
d1073 1
a1073 1
        /* Deal with the one-dimensional case separately for efficiency. */
d1093 1
a1093 1
        if (!edge && tabvox(tab, wp, 0, 0x0) == 0) {
d1160 3
a1162 3
/*----------------------------------------------------------------------------
* Convenience routine to deal with of edge effects in tabprm::p0.
*---------------------------------------------------------------------------*/
d1164 1
a1164 1
int tabedge(struct tabprm* tab)
a1172 2
      /* p0 has been incremented beyond the end of the row, point it to the
         next one. */
d1176 1
a1176 1
      /* p0 is sitting at the end of a non-degenerate row. */
d1184 3
a1186 28
/*----------------------------------------------------------------------------
* Quick test to see whether the world coordinate indicated by wp could lie
* somewhere along (or near) the row of the image indexed by tabprm::p0.
* Return 0 if so, 1 otherwise.
*
* tabprm::p0 selects a particular row of the image, p0[0] being ignored (i.e.
* treated as zero).  Adjacent rows that delimit a row of "voxels" are formed
* by incrementing elements other than p0[0] in all binary combinations.  N.B.
* these are not the same as the voxels (pixels) that are indexed by, and
* centred on, integral pixel coordinates in FITS. 
*
* To see why it is necessary to examine the adjacent rows, consider the 2-D
* case where the first world coordinate element is constant along each row.
* If the first element of wp has value 0.5, and its value in the row indexed
* by p0 has value 0, and in the next row it has value 1, then it is clear that
* the solution lies in neither row but somewhere between them.  Thus both rows
* will be involved in finding the solution.
*
* tabprm::extrema is the address of the first element of a 1-D array that
* records the minimum and maximum value of each element of the coordinate
* vector in each row of the coordinate array, treated as though it were
* defined as
*
*   double extrema[K_M]...[K_2][2][M]
*
* The minimum is recorded in the first element of the compressed K_1
* dimension, then the maximum.
*---------------------------------------------------------------------------*/
d1188 2
a1189 1
int tabrow(struct tabprm* tab, const double *wp)
d1193 1
a1193 1
  unsigned int eq, gt, lt;
d1199 1
a1199 6
  /* The number of corners in a "voxel".  We need examine only half this
     number of rows.  The extra factor of two will be used to select between
     the minimal and maximal values in each row. */
  nv = 1 << M;

  eq = 0;
d1202 2
d1205 1
a1205 1
    /* Find the index into tabprm::extrema for this row. */
a1209 2

      /* Select the row. */
a1214 1
    /* The K_1 dimension has length 2 (see prologue). */
d1216 2
d1219 2
a1220 13
    /* Select the minimum on even numbered iterations, else the maximum. */
    if (iv & 1) offset++;

    /* The last dimension has length M (see prologue). */
    offset *= M;

    /* Address of the extremal elements (min or max) for this row. */
    cp = tab->extrema + offset;

    /* For each coordinate element, we only need to find one row where its
       minimum value is less than that of wp, and one row where the maximum
       value is greater.  That doesn't mean that there is a solution, only
       that there might be. */
a1221 1
      /* Apply the axis mapping. */
a1222 2

      /* Finally the test itself; set bits in the bitmask. */
d1224 1
a1224 1
        eq |= (1 << m);
d1232 2
a1233 3
    /* Have all bits been switched on? */
    if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
      /* A solution could lie within this row of voxels. */
d1236 7
d1249 1
a1249 17
/*----------------------------------------------------------------------------
* Does the world coordinate indicated by wp lie within the voxel indexed by
* tabprm::p0?  If so, do a binary chop of the interior of the voxel to find
* it and return 0, with tabprm::delta set to the solution.  Else return 1.
*
* As in tabrow(), a "voxel" is formed by incrementing the elements of
* tabprm::p0 in all binary combinations.  Note that these are not the same as
* the voxels (pixels) that are indexed by, and centred on, integral pixel
* coordinates in FITS. 
*  
* tabvox() calls itself recursively.  When called from outside, level, being
* the level of recursion, should be given as zero.  vox is the address of a
* work array (vox2) used during recursive calls to dissect the voxel.  It is
* ignored when tabvox() is called from outside (level == 0).
*
* It is assumed that the image dimensions are no greater than 16.
----------------------------------------------------------------------------*/
d1251 6
a1256 5
int tabvox(
  struct tabprm* tab,
  const double *wp,
  int level,
  unsigned int *vox)
a1265 3
  /* The number of corners in a voxel. */
  nv = 1 << M;

d1271 1
a1271 3
  /* Could the coordinate lie within this voxel (level == 0) or sub-voxel
     (level > 0)?  We use the fact that with linear interpolation the
     coordinate elements are extremal in a corner and test each one. */
d1275 1
d1277 1
a1277 1
    /* Select a corner of the sub-voxel. */
a1280 1

a1285 3
    /* Compute the coordinates of this corner of the sub-voxel by linear
       interpolation using the weighting algorithm described in Sect. 3.4 of
       WCS Paper IV. */
a1286 2
      /* Find the index into tabprm::coord for this corner of the parent
         voxel. */
a1312 1
      /* Apply the axis mapping. */
a1313 2

      /* Finally the test itself; set bits in the bitmask. */
d1324 1
a1324 1
      /* We've stumbled across a solution in this corner of the sub-voxel. */
a1330 1
  /* Could the coordinate lie within this sub-voxel? */
d1332 1
a1332 1
    /* Yes it could, but does it? */
a1333 1
    /* Is it time to stop the recursion? */
d1335 1
a1335 1
      /* We have a solution, squeeze out the last bit of juice. */
d1344 1
a1344 1
    /* Subdivide the sub-voxel and try again for each subdivision. */
a1345 1
      /* Select the subdivision. */
a1352 1
      /* Recurse. */
d1359 1
a1359 1
  /* No solution in this sub-)voxel. */
@


4.6.1.6
log
@Sped up tabvox() by about 50% by precomputing the addresses of the
coordinates of each corner of the voxel in tabs2x() and passing them
to it.
@
text
@d1028 1
a1028 1
  int tabvox(struct tabprm *, const double *, int, double **, unsigned int *);
d1030 2
a1031 2
  int edge, i, ic, iv, k, *Km, M, m, n, nv, offset, status;
  double *Psi, psi_m, **tabcoord, upsilon;
a1044 5
  if (M > 1) {
    nv = 1 << M;
    tabcoord = calloc(nv, sizeof(double *));
  }

d1092 4
a1095 17
        /* Multi-dimensional tables are harder. */
        if (!edge) {
          /* Addresses of the coordinates for each corner of the "voxel". */
          for (iv = 0; iv < nv; iv++) {
            offset = 0;
            for (m = M-1; m >= 0; m--) {
              offset *= tab->K[m];
              offset += tab->p0[m];
              if ((iv & (1 << m)) && (tab->K[m] > 1)) offset++;
            }
            tabcoord[iv] = tab->coord + offset*M;
          }

          if (tabvox(tab, wp, 0, tabcoord, 0x0) == 0) {
            /* Found a solution. */
            break;
          }
a1156 2
  if (M > 1) free(tabcoord);

d1298 3
a1300 5
* the level of recursion, should be given as zero.  tabcoord is an array
* holding the addresses of the coordinates for each corner of the voxel.
* vox is the address of a work array (vox2) used during recursive calls to
* dissect the voxel.  It is ignored when tabvox() is called from outside
* (level == 0).
d1305 1
a1305 1
int tabvox( 
a1308 1
  double **tabcoord,
d1348 3
a1350 1
      /* Find the weight for this corner of the parent voxel. */
d1353 2
d1356 1
d1365 1
a1365 2
      /* Add its contribution to each coordinate element. */
      cp = tabcoord[jv];
d1423 1
a1423 1
      if (tabvox(tab, wp, level+1, tabcoord, vox2) == 0) {
@


4.6.1.7
log
@In tabset(), do minor extrapolation past the ends of each row when
determining the extrema.  In tabs2x(), if no solution is found then
do minor extrapolation past the ends of each row.  Only the 1-D case
is implemented, multi-dimensional tables remain to be done.
@
text
@d627 1
a627 1
  double *dcrd, *dmax, *dmin, dPsi, dval, *Psi;
d781 1
a781 18
      if (tab->K[0] > 1) {
        /* Extrapolate a little before the start of the row. */
        Psi = tab->index[0];
        if (Psi == 0x0) {
          dPsi = 1.0;
        } else {
          dPsi = Psi[1] - Psi[0];
        }

        dval = *dcrd;
        if (dPsi != 0.0) {
          dval -= 0.5 * (*(dcrd+M) - *dcrd)/dPsi;
        }

        *(dmax+m) = *(dmin+m) = dval;
      } else {
        *(dmax+m) = *(dmin+m) = *dcrd;
      }
d784 1
a784 2
    dcrd -= M;
    for (i = 0; i < tab->K[0]; i++) {
a787 18

        if (tab->K[0] > 1 && i == tab->K[0]-1) {
          /* Extrapolate a little beyond the end of the row. */
          Psi = tab->index[0];
          if (Psi == 0x0) {
            dPsi = 1.0;
          } else {
            dPsi = Psi[i] - Psi[i-1];
          }

          dval = *dcrd;
          if (dPsi != 0.0) {
            dval += 0.5 * (*dcrd - *(dcrd-M))/dPsi;
          }

          if (*(dmax+m) < dval) *(dmax+m) = dval;
          if (*(dmin+m) > dval) *(dmin+m) = dval;
        }
d1031 1
a1031 1
  double *dcrd, delta, *Psi, psi_m, **tabcoord, upsilon;
a1123 35
      /* Coordinate not found; allow minor extrapolation. */
      if (M == 1) {
        /* Should there be a solution? */
        if (tab->extrema[0] <= *wp && *wp <= tab->extrema[1]) {
          dcrd = tab->coord;
          for (i = 0; i < 2; i++) {
            if (i) dcrd += tab->K[0] - 2;

            delta = (*wp - *dcrd) / (*(dcrd+1) - *dcrd);

            if (i == 0) {
              if (-0.5 <= delta && delta <= 0.0) {
                tab->p0[0] = 0;
                tab->delta[0] = delta;
                ic = 0;
                break;
              }
            } else {
              if (1.0 <= delta && delta <= 1.5) {
                tab->p0[0] = tab->K[0] - 1;
                tab->delta[0] = delta - 1.0;
                ic = 0;
              }
            }
          }
        }

      } else {
        /* Multi-dimensional tables. */
        /* >>> TBD <<< */
      }
    }


    if (ic == tab->nc) {
d1335 1
a1335 1
  int i, iv, jv, M, m, nv;
@


4.6.1.8
log
@Minor tweakette for previous change.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.6.1.7 2011/02/04 06:29:24 cal103 Exp cal103 $
d1444 1
a1444 1
      for (m = 0; m < M; m++) {
@


4.5
log
@WCSLIB 4.5
@
text
@d3 1
a3 1
  WCSLIB 4.5 - an implementation of the FITS WCS standard.
d31 1
a31 1
  $Id: tab.c,v 4.4.1.2 2010/01/19 03:42:50 cal103 Exp cal103 $
@


4.5.1.1
log
@WCSLIB 4.5 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.5 2010/07/16 07:01:25 cal103 Exp $
@


4.4
log
@WCSLIB 4.4
@
text
@d3 2
a4 2
  WCSLIB 4.4 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2009, Mark Calabretta
d31 1
a31 1
  $Id: tab.c,v 4.3.1.2 2009/07/22 04:28:39 cal103 Exp cal103 $
@


4.4.1.1
log
@WCSLIB 4.4 development branch.
@
text
@d31 1
a31 1
  $Id: tab.c,v 4.4 2009/08/06 07:41:33 cal103 Exp $
@


4.4.1.2
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2010, Mark Calabretta
d31 1
a31 1
  $Id: tab.c,v 4.4.1.1 2009/08/10 08:52:49 cal103 Exp cal103 $
@


4.3
log
@WCSLIB 4.3
@
text
@d3 2
a4 2
    WCSLIB 4.3 - an implementation of the FITS WCS standard.
    Copyright (C) 1995-2007, Mark Calabretta
d6 1
a6 1
    This file is part of WCSLIB.
d8 24
a31 24
    WCSLIB is free software: you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by the
    Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
    more details.

    You should have received a copy of the GNU Lesser General Public License
    along with WCSLIB.  If not, see <http://www.gnu.org/licenses/>.

    Correspondence concerning WCSLIB may be directed to:
       Internet email: mcalabre@@atnf.csiro.au
       Postal address: Dr. Mark Calabretta
                       Australia Telescope National Facility, CSIRO
                       PO Box 76
                       Epping NSW 1710
                       AUSTRALIA

    Author: Mark Calabretta, Australia Telescope National Facility
    http://www.atnf.csiro.au/~mcalabre/index.html
    $Id: tab.c,v 4.2.1.6 2007/12/03 05:02:17 cal103 Exp cal103 $
d46 6
a51 6
   "Success",
   "Null tabprm pointer passed",
   "Memory allocation failed",
   "Invalid tabular parameters",
   "One or more of the x coordinates were invalid",
   "One or more of the world coordinates were invalid"};
d58 2
a59 2
   int k, m, N;
   double *dp;
d61 1
a61 1
   if (tab == 0x0) return 1;
d63 70
a132 3
   if (M <= 0) {
      return 3;
   }
d134 15
a148 3
   /* Determine the total number of elements in the coordinate array. */
   if (K) {
      N = M;
d150 15
a164 67
      for (m = 0; m < M; m++) {
         if (K[m] < 0) {
            return 3;
         }

         N *= K[m];
      }

   } else {
      /* Axis lengths as yet unknown. */
      N = 0;
   }


   /* Initialize memory management. */
   if (tab->flag == -1 || tab->m_flag != TABSET) {
      tab->m_flag  = 0;
      tab->m_M     = 0;
      tab->m_N     = 0;
      tab->m_K     = 0x0;
      tab->m_map   = 0x0;
      tab->m_crval = 0x0;
      tab->m_index = 0x0;
      tab->m_indxs = 0x0;
      tab->m_coord = 0x0;

   } else {
      /* Clear any outstanding signals set by wcstab(). */
      for (m = 0; m < tab->m_M; m++) {
         if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0;
      }

      if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0;
   }

   if (tab->flag == -1) {
      tab->sense   = 0x0;
      tab->p0      = 0x0;
      tab->delta   = 0x0;
      tab->extrema = 0x0;
      tab->set_M   = 0;
   }


   /* Allocate memory for arrays if required. */
   if (alloc ||
       tab->K == 0x0 ||
       tab->map == 0x0 ||
       tab->crval == 0x0 ||
       tab->index == 0x0 ||
       tab->coord == 0x0) {

      /* Was sufficient allocated previously? */
      if (tab->m_flag == TABSET && (tab->m_M < M || tab->m_N < N)) {
         /* No, free it. */
         tabfree(tab);
      }

      if (alloc || tab->K == 0x0) {
         if (tab->m_K) {
            /* In case the caller fiddled with it. */
            tab->K = tab->m_K;

         } else {
            if (!(tab->K = calloc(M, sizeof(int)))) {
               return 2;
            }
d166 15
a180 5
            tab->m_flag = TABSET;
            tab->m_M = M;
            tab->m_K = tab->K;
         }
      }
d182 21
a202 75
      if (alloc || tab->map == 0x0) {
         if (tab->m_map) {
            /* In case the caller fiddled with it. */
            tab->map = tab->m_map;

         } else {
            if (!(tab->map = calloc(M, sizeof(int)))) {
               return 2;
            }

            tab->m_flag = TABSET;
            tab->m_M = M;
            tab->m_map = tab->map;
         }
      }

      if (alloc || tab->crval == 0x0) {
         if (tab->m_crval) {
            /* In case the caller fiddled with it. */
            tab->crval = tab->m_crval;

         } else {
            if (!(tab->crval = calloc(M, sizeof(double)))) {
               return 2;
            }

            tab->m_flag = TABSET;
            tab->m_M = M;
            tab->m_crval = tab->crval;
         }
      }

      if (alloc || tab->index == 0x0) {
         if (tab->m_index) {
            /* In case the caller fiddled with it. */
            tab->index = tab->m_index;

         } else {
            if (!(tab->index = calloc(M, sizeof(double *)))) {
               return 2;
            }

            tab->m_flag = TABSET;
            tab->m_M = M;
            tab->m_N = N;
            tab->m_index = tab->index;

            if (!(tab->m_indxs = calloc(M, sizeof(double *)))) {
               return 2;
            }

            /* Recall that calloc() initializes these pointers to zero. */
            if (K) {
               for (m = 0; m < M; m++) {
                  if (K[m]) {
                     if (!(tab->index[m] = calloc(K[m], sizeof(double)))) {
                        return 2;
                     }

                     tab->m_indxs[m] = tab->index[m];
                  }
               }
            }
         }
      }

      if (alloc || tab->coord == 0x0) {
         if (tab->m_coord) {
            /* In case the caller fiddled with it. */
            tab->coord = tab->m_coord;

         } else if (N) {
            if (!(tab->coord = calloc(N, sizeof(double)))) {
               return 2;
            }
d204 1
a204 21
            tab->m_flag = TABSET;
            tab->m_M = M;
            tab->m_N = N;
            tab->m_coord = tab->coord;
         }
      }
   }

   tab->flag = 0;
   tab->M = M;

   /* Set defaults. */
   for (m = 0; m < M; m++) {
      tab->map[m] = -1;
      tab->crval[m] = 0.0;

      if (K) {
         tab->K[m] = K[m];
         if ((dp = tab->index[m])) {
            for (k = 0; k < K[m]; k++) {
               *(dp++) = k;
d206 2
a207 3
         }
      } else {
         tab->K[m] = 0;
d209 1
a209 1
   }
d211 42
a252 4
   /* Initialize the coordinate array. */
   for (dp = tab->coord; dp < tab->coord + N; dp++) {
      *dp = UNDEFINED;
   }
d254 1
a254 1
   return 0;
d262 1
a262 1
   int m, M, N;
d264 1
a264 1
   if (tab == 0x0) return 1;
d266 4
a269 4
   if (tab->M == 0 || tab->K == 0x0) {
      /* Should have been set by this time. */
      return 2;
   }
d272 5
a276 5
   N = M = tab->M;
   for (m = 0; m < M; m++) {
      if (tab->K[m] < 0) {
         return 3;
      }
d278 2
a279 2
      N *= tab->K[m];
   }
d282 13
a294 6
   if (tab->m_M == 0) {
      tab->m_M = M;
   } else if (tab->m_M < M) {
      /* Only possible if the user changed M. */
      return 2;
   }
d296 5
a300 6
   if (tab->m_N == 0) {
      tab->m_N = N;
   } else if (tab->m_N < N) {
      /* Only possible if the user changed K[]. */
      return 2;
   }
d302 5
a306 5
   if (tab->m_K == 0x0) {
      if ((tab->m_K = tab->K)) {
         tab->m_flag = TABSET;
      }
   }
d308 5
a312 5
   if (tab->m_map == 0x0) {
      if ((tab->m_map = tab->map)) {
         tab->m_flag = TABSET;
      }
   }
d314 5
a318 5
   if (tab->m_crval == 0x0) {
      if ((tab->m_crval = tab->crval)) {
         tab->m_flag = TABSET;
      }
   }
d320 4
a323 3
   if (tab->m_index == 0x0) {
      if ((tab->m_index = tab->index)) {
         tab->m_flag = TABSET;
d325 2
a326 1
   }
d328 5
a332 7
   for (m = 0; m < tab->m_M; m++) {
      if (tab->m_indxs[m] == 0x0 || tab->m_indxs[m] == (double *)0x1) {
         if ((tab->m_indxs[m] = tab->index[m])) {
            tab->m_flag = TABSET;
         }
      }
   }
d334 1
a334 5
   if (tab->m_coord == 0x0 || tab->m_coord == (double *)0x1) {
      if ((tab->m_coord = tab->coord)) {
         tab->m_flag = TABSET;
      }
   }
d336 1
a336 3
   tab->flag = 0;

   return 0;
d344 2
a345 4
   int k, m, M, n, N, status;
   double *dstp, *srcp;

   if (tabsrc == 0x0) return 1;
d347 1
a347 4
   M = tabsrc->M;
   if (M <= 0) {
      return 2;
   }
d349 30
a378 25
   if ((status = tabini(alloc, M, tabsrc->K, tabdst))) {
      return status;
   }

   N = M;
   for (m = 0; m < M; m++) {
      tabdst->map[m]   = tabsrc->map[m];
      tabdst->crval[m] = tabsrc->crval[m];
      N *= tabsrc->K[m];
   }

   for (m = 0; m < M; m++) {
      if ((srcp = tabsrc->index[m])) {
         dstp = tabdst->index[m];
         for (k = 0; k < tabsrc->K[m]; k++) {
            *(dstp++) = *(srcp++);
         }
      }
   }

   srcp = tabsrc->coord;
   dstp = tabdst->coord;
   for (n = 0; n < N; n++) {
      *(dstp++) = *(srcp++);
   }
d380 1
a380 1
   return 0;
d388 1
a388 11
   int m;

   if (tab == 0x0) return 1;

   if (tab->flag != -1) {
      /* Clear any outstanding signals set by wcstab(). */
      for (m = 0; m < tab->m_M; m++) {
         if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0;
      }

      if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0;
d390 1
a390 7
      /* Free memory allocated by tabini(). */
      if (tab->m_flag == TABSET) {
         if (tab->K     == tab->m_K)     tab->K = 0x0;
         if (tab->map   == tab->m_map)   tab->map = 0x0;
         if (tab->crval == tab->m_crval) tab->crval = 0x0;
         if (tab->index == tab->m_index) tab->index = 0x0;
         if (tab->coord == tab->m_coord) tab->coord = 0x0;
d392 53
a444 3
         if (tab->m_K)     free(tab->m_K);
         if (tab->m_map)   free(tab->m_map);
         if (tab->m_crval) free(tab->m_crval);
d446 1
a446 33
         if (tab->m_index) {
            for (m = 0; m < tab->m_M; m++) {
               if (tab->m_indxs[m]) free(tab->m_indxs[m]);
            }
            free(tab->m_index);
            free(tab->m_indxs);
         }

         if (tab->m_coord) free(tab->m_coord);
      }

      /* Free memory allocated by tabset(). */
      if (tab->sense)   free(tab->sense);
      if (tab->p0)      free(tab->p0);
      if (tab->delta)   free(tab->delta);
      if (tab->extrema) free(tab->extrema);
   }

   tab->m_flag  = 0;
   tab->m_M     = 0;
   tab->m_N     = 0;
   tab->m_K     = 0x0;
   tab->m_map   = 0x0;
   tab->m_crval = 0x0;
   tab->m_index = 0x0;
   tab->m_indxs = 0x0;
   tab->m_coord = 0x0;

   tab->sense   = 0x0;
   tab->p0      = 0x0;
   tab->delta   = 0x0;
   tab->extrema = 0x0;
   tab->set_M   = 0;
d448 1
a448 3
   tab->flag = 0;

   return 0;
d456 48
a503 127
   char   *cp, text[128];
   int    j, k, m, n, nd;
   double *dp;

   if (tab == 0x0) return 1;

   if (tab->flag != TABSET) {
      printf("The tabprm struct is UNINITIALIZED.\n");
      return 0;
   }

   printf("       flag: %d\n", tab->flag);
   printf("          M: %d\n", tab->M);

   /* Array dimensions. */
   printf("          K: %p\n", (void *)tab->K);
   printf("            ");
   for (m = 0; m < tab->M; m++) {
      printf("%6d", tab->K[m]);
   }
   printf("\n");

   /* Map vector. */
   printf("        map: %p\n", (void *)tab->map);
   printf("            ");
   for (m = 0; m < tab->M; m++) {
      printf("%6d", tab->map[m]);
   }
   printf("\n");

   /* Reference index value. */
   printf("      crval: %p\n", (void *)tab->crval);
   printf("            ");
   for (m = 0; m < tab->M; m++) {
      printf("  %- 11.5g", tab->crval[m]);
   }
   printf("\n");

   /* Index vectors. */
   printf("      index: %p\n", (void *)tab->index);
   for (m = 0; m < tab->M; m++) {
      printf("   index[%d]: %p", m, (void *)tab->index[m]);
      if (tab->index[m]) {
         for (k = 0; k < tab->K[m]; k++) {
            if (k%5 == 0) {
               printf("\n            ");
            }
            printf("  %- 11.5g", tab->index[m][k]);
         }
         printf("\n");
      }
   }

   /* Coordinate array. */
   printf("      coord: %p\n", (void *)tab->coord);
   dp = tab->coord;
   for (n = 0; n < tab->nc; n++) {
      /* Array index. */
      j = n;
      cp = text;
      for (m = 0; m < tab->M; m++) {
         nd = (tab->K[m] < 10) ? 1 : 2;
         sprintf(cp, ",%*d", nd, j % tab->K[m] + 1);
         j /= tab->K[m];
         cp += strlen(cp);
      }

      printf("             (*%s)", text);
      for (m = 0; m < tab->M; m++) {
         printf("  %- 11.5g", *(dp++));
      }
      printf("\n");
   }

   printf("         nc: %d\n", tab->nc);

   if (tab->sense == 0x0) {
      printf("      sense: (nil)\n");
   } else {
      printf("      sense: %p\n", (void *)tab->sense);
      printf("            ");
      for (m = 0; m < tab->M; m++) {
         printf("%6d", tab->sense[m]);
      }
      printf("\n");
   }

   if (tab->p0 == 0x0) {
      printf("         p0: (nil)\n");
   } else {
      printf("         p0: %p\n", (void *)tab->p0);
      printf("            ");
      for (m = 0; m < tab->M; m++) {
         printf("%6d", tab->p0[m]);
      }
      printf("\n");
   }

   if (tab->delta == 0x0) {
      printf("      delta: (nil)\n");
   } else {
      printf("      delta: %p\n", (void *)tab->delta);
      printf("            ");
      for (m = 0; m < tab->M; m++) {
         printf("  %- 11.5g", tab->delta[m]);
      }
      printf("\n");
   }

   printf("    extrema: %p\n", (void *)tab->extrema);
   dp = tab->extrema;
   for (n = 0; n < tab->nc/tab->K[0]; n++) {
      /* Array index. */
      j = n;
      cp = text;
      *cp = '\0';
      for (m = 1; m < tab->M; m++) {
         nd = (tab->K[m] < 10) ? 1 : 2;
         sprintf(cp, ",%*d", nd, j % tab->K[m] + 1);
         j /= tab->K[m];
         cp += strlen(cp);
      }

      printf("             (*,*%s)", text);
      for (m = 0; m < 2*tab->M; m++) {
         if (m == tab->M) printf("->  ");
         printf("  %- 11.5g", *(dp++));
d506 2
a507 27
   }

   /* Memory management. */
   printf("     m_flag: %d\n", tab->m_flag);
   printf("        m_M: %d\n", tab->m_M);
   printf("        m_N: %d\n", tab->m_N);

   printf("        m_K: %p", (void *)tab->m_K);
   if (tab->m_K == tab->K) printf("  (= K)");
   printf("\n");

   printf("      m_map: %p", (void *)tab->m_map);
   if (tab->m_map == tab->map) printf("  (= map)");
   printf("\n");

   printf("    m_crval: %p", (void *)tab->m_crval);
   if (tab->m_crval == tab->crval) printf("  (= crval)");
   printf("\n");

   printf("    m_index: %p", (void *)tab->m_index);
   if (tab->m_index == tab->index) printf("  (= index)");
   printf("\n");
   for (m = 0; m < tab->M; m++) {
      printf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]);
      if (tab->m_indxs[m] == tab->index[m]) printf("  (= index[%d])", m);
      printf("\n");
   }
d509 107
a615 3
   printf("    m_coord: %p", (void *)tab->m_coord);
   if (tab->m_coord == tab->coord) printf("  (= coord)");
   printf("\n");
d617 1
a617 1
   return 0;
d625 2
a626 2
   int i, ic, k, *Km, m, M, ne;
   double *dcrd, *dmax, *dmin, *Psi;
d628 1
a628 1
   if (tab == 0x0) return 1;
d630 13
a642 2
   /* Check the number of tabular coordinate axes. */
   if ((M = tab->M) < 1) {
d644 1
a644 1
   }
d646 15
a660 4
   /* Check the axis lengths. */
   if (!tab->K) {
      return 2;
   }
d662 12
a673 5
   tab->nc = 1;
   for (m = 0; m < M; m++) {
      if (tab->K[m] < 1) {
         return 3;
      }
d675 13
a687 3
      /* Number of coordinate vectors in the coordinate array. */
      tab->nc *= tab->K[m];
   }
d689 2
a690 2
   /* Check that the map vector is sensible. */
   if (!tab->map) {
d692 1
a692 1
   }
d694 4
a697 6
   for (m = 0; m < M; m++) {
      i = tab->map[m];
      if (i < 0) {
         return 3;
      }
   }
d699 3
a701 2
   /* Check memory allocation for the remaining vectors. */
   if (!tab->crval || !tab->index || !tab->coord) {
d703 1
a703 1
   }
d705 7
a711 7
   /* Take memory if signalled to by wcstab(). */
   for (m = 0; m < tab->m_M; m++) {
      if (tab->m_indxs[m] == (double *)0x1 &&
         (tab->m_indxs[m] = tab->index[m])) {
         tab->m_flag = TABSET;
      }
   }
d713 2
a714 4
   if (tab->m_coord == (double *)0x1 &&
      (tab->m_coord = tab->coord)) {
      tab->m_flag = TABSET;
   }
d716 9
d726 12
a737 7
   /* Allocate memory for work vectors. */
   if (tab->flag != TABSET || tab->set_M < M) {
      /* Free memory that may have been allocated previously. */
      if (tab->sense)   free(tab->sense);
      if (tab->p0)      free(tab->p0);
      if (tab->delta)   free(tab->delta);
      if (tab->extrema) free(tab->extrema);
d739 10
a748 9
      /* Allocate memory for internal arrays. */
      if (!(tab->sense = calloc(M, sizeof(int)))) {
         return 2;
      }

      if (!(tab->p0 = calloc(M, sizeof(int)))) {
         free(tab->sense);
         return 2;
      }
d750 8
a757 62
      if (!(tab->delta = calloc(M, sizeof(double)))) {
         free(tab->sense);
         free(tab->p0);
         return 2;
      }

      ne = M * tab->nc * 2 / tab->K[0];
      if (!(tab->extrema = calloc(ne, sizeof(double)))) {
         free(tab->sense);
         free(tab->p0);
         free(tab->delta);
         return 2;
      }

      tab->set_M = M;
   }

   /* Check that the index vectors are monotonic. */
   Km = tab->K;
   for (m = 0; m < M; m++, Km++) {
      tab->sense[m] = 0;

      if (*Km > 1) {
         if ((Psi = tab->index[m]) == 0) {
            /* Default indexing. */
            tab->sense[m] = 1;

         } else {
            for (k = 0; k < *Km-1; k++) {
               switch (tab->sense[m]) {
               case 0:
                  if (Psi[k] < Psi[k+1]) {
                     /* Monotonic increasing. */
                     tab->sense[m] = 1;
                  } else if (Psi[k] > Psi[k+1]) {
                     /* Monotonic decreasing. */
                     tab->sense[m] = -1;
                  }
                  break;

               case 1:
                  if (Psi[k] > Psi[k+1]) {
                     /* Should be monotonic increasing. */
                     free(tab->sense);
                     free(tab->p0);
                     free(tab->delta);
                     free(tab->extrema);
                     return 3;
                  }
                  break;

               case -1:
                  if (Psi[k] < Psi[k+1]) {
                     /* Should be monotonic decreasing. */
                     free(tab->sense);
                     free(tab->p0);
                     free(tab->delta);
                     free(tab->extrema);
                     return 3;
                  }
                  break;
               }
d759 23
a781 1
         }
d783 1
a783 15
         if (tab->sense[m] == 0) {
            free(tab->sense);
            free(tab->p0);
            free(tab->delta);
            free(tab->extrema);
            return 3;
         }
      }
   }

   /* Deduce the extremal values of the coordinate elements in each row. */
   dcrd = tab->coord;
   dmin = tab->extrema;
   dmax = tab->extrema + M;
   for (ic = 0; ic < tab->nc; ic += tab->K[0]) {
d785 2
a786 8
         *(dmax+m) = *(dmin+m) = *dcrd;
      }

      for (i = 1; i < tab->K[0]; i++) {
         for (m = 0; m < M; m++, dcrd++) {
            if (*(dmax+m) < *dcrd) *(dmax+m) = *dcrd;
            if (*(dmin+m) > *dcrd) *(dmin+m) = *dcrd;
         }
d788 1
d790 3
a792 3
      dmin += 2*M;
      dmax += 2*M;
   }
d794 1
a794 1
   tab->flag = TABSET;
d796 1
a796 1
   return 0;
d802 6
a807 6
   struct tabprm *tab,
   int ncoord,
   int nelem,
   const double x[],
   double world[],
   int stat[])
d810 29
a838 25
   int i, iv, k, *Km, m, M, n, nv, offset, p0, status;
   double *coord, *Psi, psi_m, upsilon, wgt;
   register int *statp;
   register const double *xp;
   register double *wp;

   /* Initialize if required. */
   if (tab == 0x0) return 1;
   if (tab->flag != TABSET) {
      if ((status = tabset(tab))) return status;
   }

   /* This is used a lot. */
   M = tab->M;

   status = 0;
   xp = x;
   wp = world;
   statp = stat;
   for (n = 0; n < ncoord; n++) {
      /* Determine the indexes. */
      Km = tab->K;
      for (m = 0; m < M; m++, Km++) {
         i = tab->map[m];
         psi_m = *(xp+i) + tab->crval[m];
d840 4
a843 2
         if ((Psi = tab->index[m]) == 0) {
            /* Default indexing is simple. */
d845 5
d851 27
a877 10
         } else {
            if (*Km == 1) {
               /* Index vector is degenerate. */
               if (Psi[0]-0.5 <= psi_m && psi_m <= Psi[0]+0.5) {
                  upsilon = psi_m;
               } else {
                  *statp = 1;
                  status = 4;
                  goto next;
               }
d880 38
a917 81
               /* Interpolate in the indexing vector. */
               if (tab->sense[m] == 1) {
                  /* Monotonic increasing index values. */
                  if (psi_m < Psi[0]) {
                     if (Psi[0] - 0.5*(Psi[1]-Psi[0]) <= psi_m) {
                        /* Allow minor extrapolation. */
                        k = 0;

                     } else {
                        /* Index is out of range. */
                        *statp = 1;
                        status = 4;
                        goto next;
                     }

                  } else if (Psi[*Km-1] < psi_m) {
                     if (psi_m <= Psi[*Km-1] + 0.5*(Psi[*Km-1]-Psi[*Km-2])) {
                        /* Allow minor extrapolation. */
                        k = *Km - 2;

                     } else {
                        /* Index is out of range. */
                        *statp = 1;
                        status = 4;
                        goto next;
                     }

                  } else {
                     for (k = 0; k < *Km-1; k++) {
                        if (psi_m < Psi[k]) {
                           continue;
                        }
                        if (Psi[k] == psi_m && psi_m < Psi[k+1]) {
                           break;
                        }
                        if (Psi[k] < psi_m && psi_m <= Psi[k+1]) {
                           break;
                        }
                     }
                  }

               } else {
                  /* Monotonic decreasing index values. */
                  if (psi_m > Psi[0]) {
                     if (Psi[0] + 0.5*(Psi[0]-Psi[1]) >= psi_m) {
                        /* Allow minor extrapolation. */
                        k = 0;

                     } else {
                        /* Index is out of range. */
                        *statp = 1;
                        status = 4;
                        goto next;
                     }

                  } else if (psi_m < Psi[*Km-1]) {
                     if (Psi[*Km-1] - 0.5*(Psi[*Km-2]-Psi[*Km-1]) <= psi_m) {
                        /* Allow minor extrapolation. */
                        k = *Km - 2;

                     } else {
                        /* Index is out of range. */
                        *statp = 1;
                        status = 4;
                        goto next;
                     }

                  } else {
                     for (k = 0; k < *Km-1; k++) {
                        if (psi_m > Psi[k]) {
                           continue;
                        }
                        if (Psi[k] == psi_m && psi_m > Psi[k+1]) {
                           break;
                        }
                        if (Psi[k] > psi_m && psi_m >= Psi[k+1]) {
                           break;
                        }
                     }
                  }
               }
d919 12
a930 1
               upsilon = k + (psi_m - Psi[k]) / (Psi[k+1] - Psi[k]);
d932 1
a932 1
         }
d934 3
a936 11
         if (upsilon < -0.5 || upsilon > *Km - 0.5) {
            /* Index out of range. */
            *statp = 1;
            status = 4;
            goto next;
         }

         /* Fiducial array indices and fractional offset. */
         p0 = (int)floor(upsilon);
         tab->p0[m] = p0;
         tab->delta[m] = upsilon - p0;
d938 5
a942 7
         if (p0 == -1) {
           tab->p0[m] += 1;
           tab->delta[m] -= 1.0;
         } else if (p0 == *Km-1 && *Km > 1) {
           tab->p0[m] -= 1;
           tab->delta[m] += 1.0;
         }
d945 4
d950 6
a955 5
      /* Now interpolate in the coordinate array; the M-dimensional linear  */
      /* interpolation algorithm is described in Sect. 3.4 of WCS Paper IV. */
      for (m = 0; m < M; m++) {
         i = tab->map[m];
         *(wp+i) = 0.0;
d957 2
d960 6
a965 16
      /* Loop over the 2^M vertices surrounding P. */
      nv = 1 << M;
      for (iv = 0; iv < nv; iv++) {
         /* Locate vertex in the coordinate array and compute its weight. */
         offset = 0;
         wgt = 1.0;
         for (m = M-1; m >= 0; m--) {
            offset *= tab->K[m];
            offset += tab->p0[m];
            if (iv & (1 << m)) {
               if (tab->K[m] > 1) offset++;
               wgt *= tab->delta[m];
            } else {
               wgt *= 1.0 - tab->delta[m];
            }
         }
d967 16
a982 1
         if (wgt == 0.0) continue;
d984 1
a984 6
         /* Add the contribution from this vertex to each element. */
         coord = tab->coord + offset*M;
         for (m = 0; m < M; m++) {
            i = tab->map[m];
            *(wp+i) += *(coord++) * wgt;
         }
d986 5
a990 1
         if (wgt == 1.0) break;
d993 4
a996 1
      *statp = 0;
d999 4
a1002 4
      xp += nelem;
      wp += nelem;
      statp++;
   }
d1004 1
a1004 1
   return status;
d1010 6
a1015 6
   struct tabprm* tab,
   int ncoord,
   int nelem,
   const double world[],
   double x[],
   int stat[])
d1018 61
a1078 75
   int tabedge(struct tabprm *);
   int tabrow(struct tabprm *, const double *);
   int tabvox(struct tabprm *, const double *, int, unsigned int *);

   int edge, i, ic, k, *Km, M, m, n, status;
   double *Psi, psi_m, upsilon;
   register int *statp;
   register const double *wp;
   register double *xp;

   /* Initialize if required. */
   if (tab == 0x0) return 1;
   if (tab->flag != TABSET) {
      if ((status = tabset(tab))) return status;
   }

   /* This is used a lot. */
   M = tab->M;


   status = 0;
   wp = world;
   xp = x;
   statp = stat;
   for (n = 0; n < ncoord; n++) {
      /* Locate this coordinate in the coordinate array. */
      edge = 0;
      for (m = 0; m < M; m++) {
         tab->p0[m] = 0;
      }

      for (ic = 0; ic < tab->nc; ic++) {
         if (tab->p0[0] == 0) {
            /* New row, could it contain a solution? */
            if (edge || tabrow(tab, wp)) {
               /* No, skip it. */
               ic += tab->K[0] - 1;
               tab->p0[1]++;
               edge = tabedge(tab);
               continue;
            }
         }

         if (M == 1) {
            /* Deal with the one-dimensional case separately. */
            if (*wp == tab->coord[0]) {
               tab->p0[0] = 0;
               tab->delta[0] = 0.0;
               break;

            } else if (ic < tab->nc - 1) {
               if (((tab->coord[ic] <= *wp && *wp <= tab->coord[ic+1]) ||
                    (tab->coord[ic] >= *wp && *wp >= tab->coord[ic+1])) &&
                    (tab->index[0] == 0 ||
                     tab->index[0][ic] != tab->index[0][ic+1])) {
                  tab->p0[0] = ic;
                  tab->delta[0] = (*wp - tab->coord[ic]) /
                                  (tab->coord[ic+1] - tab->coord[ic]);
                  break;
               }
            }

         } else {
            /* Multi-dimensional tables are much harder. */
            if (!edge && tabvox(tab, wp, 0, 0) == 0) {
               /* Found a solution. */
               break;
            }

            /* Next voxel. */
            tab->p0[0]++;
            edge = tabedge(tab);
         }
      }

a1079 4
      if (ic == tab->nc) {
         /* Coordinate not found. */
         *statp = 1;
         status = 5;
d1081 32
a1112 8
         /* Determine the intermediate world coordinates. */
         Km = tab->K;
         for (m = 0; m < M; m++, Km++) {
            upsilon = tab->p0[m] + tab->delta[m];
            if (upsilon < -0.5 || upsilon > *Km - 0.5) {
               /* Index out of range. */
               *statp = 1;
               status = 5;
d1114 4
d1119 7
a1125 17
               /* Do inverse lookup of the index vector. */
               if ((Psi = tab->index[m]) == 0) {
                  /* Default indexing. */
                  psi_m = upsilon;

               } else {
                  if (*Km == 1) {
                     /* Degenerate index vector. */
                     psi_m = Psi[0];
                  } else {
                     k = (int)upsilon;
                     psi_m = Psi[k];
                     if (k < *Km-1) {
                       psi_m += (upsilon - k) * (Psi[k+1] - Psi[k]);
                     }
                  }
               }
d1127 3
a1129 5
               i = tab->map[m];
               xp[i] = psi_m - tab->crval[m];
            }
         }
         *statp = 0;
d1131 2
d1134 4
a1137 4
      wp += nelem;
      xp += nelem;
      statp++;
   }
d1139 1
a1139 1
   return status;
d1149 1
a1149 1
   int edge, *Km, m;
d1151 11
a1161 11
   edge = 0;
   Km = tab->K;
   for (m = 0; m < tab->M; m++, Km++) {
      if (tab->p0[m] == *Km) {
         tab->p0[m] = 0;
         tab->p0[m+1]++;
      } else if (tab->p0[m] == *Km - 1 && *Km > 1) {
         /* Edge effects? */
         edge = 1;
      }
   }
d1163 1
a1163 1
   return edge;
d1174 37
a1210 43
   int iv, M, m, nv, offset;
   unsigned int eq, et, gt, lt;
   const double tol = 1.0e-10;
   double *cp, w;

   M = tab->M;

   /* Could the coordinate lie somewhere along this row of voxels? */
   lt = 0;
   gt = 0;
   eq = 0;
   nv = 1 << M;
   for (iv = 0; iv < nv; iv++) {
      /* Find the extrema at this end of the row. */
      offset = 0;
      for (m = M-1; m > 0; m--) {
         offset *= tab->K[m];
         offset += tab->p0[m];
         if (iv & (1 << m)) {
            if (tab->K[m] > 1) offset++;
         }
      }

      offset *= 2;
      offset += tab->p0[0];
      if (iv & 1 && tab->K[0] > 1) offset++;

      et = 0;
      cp = tab->extrema + offset*M;
      for (m = 0; m < M; m++, cp++) {
         w = wp[tab->map[m]];
         if (fabs(*cp - w) < tol) {
            et |= (1 << m);
         } else if (*cp < w) {
            lt |= (1 << m);
         } else if (*cp > w) {
            gt |= (1 << m);
         }
      }

      if (et == nv-1) {
         /* Solution found in a corner. */
         return 0;
d1212 1
d1214 7
a1220 2
      eq |= et;
   }
d1222 4
a1225 4
   if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
      /* A solution could lie within this row of voxels. */
      return 0;
   }
d1227 2
a1228 2
   /* No solution in this row. */
   return 1;
d1241 26
a1266 4
   int i, iv, jv, M, m, nv, offset;
   unsigned int eq, et, gt, lt, vox2[16];
   const double tol = 1.0e-10;
   double coord[16], *cp, dv, w, wgt;
d1268 13
a1280 1
   M = tab->M;
d1282 1
a1282 4
   dv = 1.0;
   for (i = 0; i < level; i++) {
      dv /= 2.0;
   }
d1284 1
a1284 7
   /* Could the coordinate lie within this voxel? */
   lt = 0;
   gt = 0;
   eq = 0;
   nv = 1 << M;
   for (iv = 0; iv < nv; iv++) {
      /* Compute the coordinates of this corner of the voxel. */
d1286 23
a1308 20
         coord[m] = 0.0;
         tab->delta[m] = level ? dv*vox[m] : 0.0;
         if (iv & (1 << m)) {
            tab->delta[m] += dv;
         }
      }

      for (jv = 0; jv < nv; jv++) {
         offset = 0;
         wgt = 1.0;
         for (m = M-1; m >= 0; m--) {
            offset *= tab->K[m];
            offset += tab->p0[m];
            if (jv & (1 << m)) {
               if (tab->K[m] > 1) offset++;
               wgt *= tab->delta[m];
            } else {
               wgt *= 1.0 - tab->delta[m];
            }
         }
d1310 2
a1311 1
         if (wgt == 0.0) continue;
d1313 2
a1314 4
         cp = tab->coord + offset*M;
         for (m = 0; m < M; m++) {
            coord[m] += *(cp++) * wgt;
         }
d1316 5
a1320 1
         if (wgt == 1.0) break;
d1323 5
a1327 2
      /* Coordinate elements are minimal or maximal in a corner. */
      et = 0;
d1329 5
a1333 39
         w = wp[tab->map[m]];
         if (fabs(coord[m] - w) < tol) {
            et |= (1 << m);
         } else if (coord[m] < w) {
            lt |= (1 << m);
         } else if (coord[m] > w) {
            gt |= (1 << m);
         }
      }

      if (et == nv-1) {
         /* Solution found in a corner. */
         return 0;
      }

      eq |= et;
   }

   if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
      /* The coordinate could lie within this voxel, but does it? */

      if (level == 31) {
         /* Stop the recursion. */
         dv /= 2.0;
         for (m = 0; m < M; m++) {
            tab->delta[m] = dv * (2.0*vox[m] + 1.0);
         }

         return 0;
      }

      /* Subdivide and try again. */
      for (iv = 0; iv < nv; iv++) {
         for (m = 0; m < M; m++) {
            vox2[m] = level ? 2*vox[m] : 0;
            if (iv & (1 << m)) {
               vox2[m]++;
            }
         }
d1335 2
a1336 3
         if (tabvox(tab, wp, level+1, vox2) == 0) {
            return 0;
         }
d1338 2
a1339 1
   }
d1341 2
a1342 2
   /* No solution in this voxel. */
   return 1;
@


4.3.1.1
log
@WCSLIB 4.3 development branch.
@
text
@d3 2
a4 2
    WCSLIB 4.4 - an implementation of the FITS WCS standard.
    Copyright (C) 1995-2008, Mark Calabretta
d31 1
a31 1
    $Id: tab.c,v 4.3 2007/12/27 05:41:36 cal103 Exp cal103 $
@


4.3.1.2
log
@Changed indentation.
@
text
@d3 2
a4 2
  WCSLIB 4.4 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2009, Mark Calabretta
d6 1
a6 1
  This file is part of WCSLIB.
d8 24
a31 24
  WCSLIB is free software: you can redistribute it and/or modify it under the
  terms of the GNU Lesser General Public License as published by the Free
  Software Foundation, either version 3 of the License, or (at your option)
  any later version.

  WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
  WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
  FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
  more details.

  You should have received a copy of the GNU Lesser General Public License
  along with WCSLIB.  If not, see <http://www.gnu.org/licenses/>.

  Correspondence concerning WCSLIB may be directed to:
    Internet email: mcalabre@@atnf.csiro.au
    Postal address: Dr. Mark Calabretta
                    Australia Telescope National Facility, CSIRO
                    PO Box 76
                    Epping NSW 1710
                    AUSTRALIA

  Author: Mark Calabretta, Australia Telescope National Facility
  http://www.atnf.csiro.au/~mcalabre/index.html
  $Id: tab.c,v 4.3.1.1 2007/12/27 13:23:47 cal103 Exp cal103 $
d46 6
a51 6
  "Success",
  "Null tabprm pointer passed",
  "Memory allocation failed",
  "Invalid tabular parameters",
  "One or more of the x coordinates were invalid",
  "One or more of the world coordinates were invalid"};
d58 2
a59 2
  int k, m, N;
  double *dp;
d61 1
a61 1
  if (tab == 0x0) return 1;
d63 97
a159 70
  if (M <= 0) {
    return 3;
  }

  /* Determine the total number of elements in the coordinate array. */
  if (K) {
    N = M;

    for (m = 0; m < M; m++) {
      if (K[m] < 0) {
        return 3;
      }

      N *= K[m];
    }

  } else {
    /* Axis lengths as yet unknown. */
    N = 0;
  }


  /* Initialize memory management. */
  if (tab->flag == -1 || tab->m_flag != TABSET) {
    tab->m_flag  = 0;
    tab->m_M     = 0;
    tab->m_N     = 0;
    tab->m_K     = 0x0;
    tab->m_map   = 0x0;
    tab->m_crval = 0x0;
    tab->m_index = 0x0;
    tab->m_indxs = 0x0;
    tab->m_coord = 0x0;

  } else {
    /* Clear any outstanding signals set by wcstab(). */
    for (m = 0; m < tab->m_M; m++) {
      if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0;
    }

    if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0;
  }

  if (tab->flag == -1) {
    tab->sense   = 0x0;
    tab->p0      = 0x0;
    tab->delta   = 0x0;
    tab->extrema = 0x0;
    tab->set_M   = 0;
  }


  /* Allocate memory for arrays if required. */
  if (alloc ||
     tab->K == 0x0 ||
     tab->map == 0x0 ||
     tab->crval == 0x0 ||
     tab->index == 0x0 ||
     tab->coord == 0x0) {

    /* Was sufficient allocated previously? */
    if (tab->m_flag == TABSET && (tab->m_M < M || tab->m_N < N)) {
      /* No, free it. */
      tabfree(tab);
    }

    if (alloc || tab->K == 0x0) {
      if (tab->m_K) {
        /* In case the caller fiddled with it. */
        tab->K = tab->m_K;
d161 34
a194 15
      } else {
        if (!(tab->K = calloc(M, sizeof(int)))) {
          return 2;
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_K = tab->K;
      }
    }

    if (alloc || tab->map == 0x0) {
      if (tab->m_map) {
        /* In case the caller fiddled with it. */
        tab->map = tab->m_map;
d196 14
a209 15
      } else {
        if (!(tab->map = calloc(M, sizeof(int)))) {
          return 2;
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_map = tab->map;
      }
    }

    if (alloc || tab->crval == 0x0) {
      if (tab->m_crval) {
        /* In case the caller fiddled with it. */
        tab->crval = tab->m_crval;
d211 4
a214 15
      } else {
        if (!(tab->crval = calloc(M, sizeof(double)))) {
          return 2;
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_crval = tab->crval;
      }
    }

    if (alloc || tab->index == 0x0) {
      if (tab->m_index) {
        /* In case the caller fiddled with it. */
        tab->index = tab->m_index;
d216 4
a219 21
      } else {
        if (!(tab->index = calloc(M, sizeof(double *)))) {
          return 2;
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_N = N;
        tab->m_index = tab->index;

        if (!(tab->m_indxs = calloc(M, sizeof(double *)))) {
           return 2;
        }

        /* Recall that calloc() initializes these pointers to zero. */
        if (K) {
          for (m = 0; m < M; m++) {
            if (K[m]) {
              if (!(tab->index[m] = calloc(K[m], sizeof(double)))) {
                return 2;
              }
d221 21
a241 1
              tab->m_indxs[m] = tab->index[m];
d243 3
a245 2
          }
        }
d247 1
a247 1
    }
d249 4
a252 42
    if (alloc || tab->coord == 0x0) {
      if (tab->m_coord) {
        /* In case the caller fiddled with it. */
        tab->coord = tab->m_coord;

      } else if (N) {
        if (!(tab->coord = calloc(N, sizeof(double)))) {
          return 2;
        }

        tab->m_flag = TABSET;
        tab->m_M = M;
        tab->m_N = N;
        tab->m_coord = tab->coord;
      }
    }
  }

  tab->flag = 0;
  tab->M = M;

  /* Set defaults. */
  for (m = 0; m < M; m++) {
    tab->map[m] = -1;
    tab->crval[m] = 0.0;

    if (K) {
      tab->K[m] = K[m];
      if ((dp = tab->index[m])) {
        for (k = 0; k < K[m]; k++) {
          *(dp++) = k;
        }
      }
    } else {
      tab->K[m] = 0;
    }
  }

  /* Initialize the coordinate array. */
  for (dp = tab->coord; dp < tab->coord + N; dp++) {
    *dp = UNDEFINED;
  }
d254 1
a254 1
  return 0;
d262 1
a262 1
  int m, M, N;
d264 1
a264 1
  if (tab == 0x0) return 1;
d266 4
a269 4
  if (tab->M == 0 || tab->K == 0x0) {
    /* Should have been set by this time. */
    return 2;
  }
d272 5
a276 5
  N = M = tab->M;
  for (m = 0; m < M; m++) {
    if (tab->K[m] < 0) {
      return 3;
    }
d278 2
a279 2
    N *= tab->K[m];
  }
d282 13
a294 13
  if (tab->m_M == 0) {
    tab->m_M = M;
  } else if (tab->m_M < M) {
    /* Only possible if the user changed M. */
    return 2;
  }

  if (tab->m_N == 0) {
    tab->m_N = N;
  } else if (tab->m_N < N) {
    /* Only possible if the user changed K[]. */
    return 2;
  }
d296 5
a300 5
  if (tab->m_K == 0x0) {
    if ((tab->m_K = tab->K)) {
      tab->m_flag = TABSET;
    }
  }
d302 5
a306 5
  if (tab->m_map == 0x0) {
    if ((tab->m_map = tab->map)) {
      tab->m_flag = TABSET;
    }
  }
d308 5
a312 5
  if (tab->m_crval == 0x0) {
    if ((tab->m_crval = tab->crval)) {
      tab->m_flag = TABSET;
    }
  }
d314 5
a318 5
  if (tab->m_index == 0x0) {
    if ((tab->m_index = tab->index)) {
      tab->m_flag = TABSET;
    }
  }
d320 5
a324 4
  for (m = 0; m < tab->m_M; m++) {
    if (tab->m_indxs[m] == 0x0 || tab->m_indxs[m] == (double *)0x1) {
      if ((tab->m_indxs[m] = tab->index[m])) {
        tab->m_flag = TABSET;
d326 1
a326 2
    }
  }
d328 5
a332 5
  if (tab->m_coord == 0x0 || tab->m_coord == (double *)0x1) {
    if ((tab->m_coord = tab->coord)) {
      tab->m_flag = TABSET;
    }
  }
d334 1
a334 1
  tab->flag = 0;
d336 1
a336 1
  return 0;
d344 4
a347 2
  int k, m, M, n, N, status;
  double *dstp, *srcp;
d349 4
a352 1
  if (tabsrc == 0x0) return 1;
d354 25
a378 30
  M = tabsrc->M;
  if (M <= 0) {
    return 2;
  }

  if ((status = tabini(alloc, M, tabsrc->K, tabdst))) {
    return status;
  }

  N = M;
  for (m = 0; m < M; m++) {
    tabdst->map[m]   = tabsrc->map[m];
    tabdst->crval[m] = tabsrc->crval[m];
    N *= tabsrc->K[m];
  }

  for (m = 0; m < M; m++) {
    if ((srcp = tabsrc->index[m])) {
      dstp = tabdst->index[m];
      for (k = 0; k < tabsrc->K[m]; k++) {
        *(dstp++) = *(srcp++);
      }
    }
  }

  srcp = tabsrc->coord;
  dstp = tabdst->coord;
  for (n = 0; n < N; n++) {
    *(dstp++) = *(srcp++);
  }
d380 1
a380 1
  return 0;
d388 11
a398 1
  int m;
d400 7
a406 1
  if (tab == 0x0) return 1;
d408 3
a410 53
  if (tab->flag != -1) {
    /* Clear any outstanding signals set by wcstab(). */
    for (m = 0; m < tab->m_M; m++) {
      if (tab->m_indxs[m] == (double *)0x1) tab->m_indxs[m] = 0x0;
    }

    if (tab->m_coord == (double *)0x1) tab->m_coord = 0x0;

    /* Free memory allocated by tabini(). */
    if (tab->m_flag == TABSET) {
      if (tab->K     == tab->m_K)     tab->K = 0x0;
      if (tab->map   == tab->m_map)   tab->map = 0x0;
      if (tab->crval == tab->m_crval) tab->crval = 0x0;
      if (tab->index == tab->m_index) tab->index = 0x0;
      if (tab->coord == tab->m_coord) tab->coord = 0x0;

      if (tab->m_K)     free(tab->m_K);
      if (tab->m_map)   free(tab->m_map);
      if (tab->m_crval) free(tab->m_crval);

      if (tab->m_index) {
        for (m = 0; m < tab->m_M; m++) {
          if (tab->m_indxs[m]) free(tab->m_indxs[m]);
        }
        free(tab->m_index);
        free(tab->m_indxs);
      }

      if (tab->m_coord) free(tab->m_coord);
    }

    /* Free memory allocated by tabset(). */
    if (tab->sense)   free(tab->sense);
    if (tab->p0)      free(tab->p0);
    if (tab->delta)   free(tab->delta);
    if (tab->extrema) free(tab->extrema);
  }

  tab->m_flag  = 0;
  tab->m_M     = 0;
  tab->m_N     = 0;
  tab->m_K     = 0x0;
  tab->m_map   = 0x0;
  tab->m_crval = 0x0;
  tab->m_index = 0x0;
  tab->m_indxs = 0x0;
  tab->m_coord = 0x0;

  tab->sense   = 0x0;
  tab->p0      = 0x0;
  tab->delta   = 0x0;
  tab->extrema = 0x0;
  tab->set_M   = 0;
d412 33
a444 1
  tab->flag = 0;
d446 3
a448 1
  return 0;
d456 127
a582 48
  char   *cp, text[128];
  int    j, k, m, n, nd;
  double *dp;

  if (tab == 0x0) return 1;

  if (tab->flag != TABSET) {
    printf("The tabprm struct is UNINITIALIZED.\n");
    return 0;
  }

  printf("       flag: %d\n", tab->flag);
  printf("          M: %d\n", tab->M);

  /* Array dimensions. */
  printf("          K: %p\n", (void *)tab->K);
  printf("            ");
  for (m = 0; m < tab->M; m++) {
    printf("%6d", tab->K[m]);
  }
  printf("\n");

  /* Map vector. */
  printf("        map: %p\n", (void *)tab->map);
  printf("            ");
  for (m = 0; m < tab->M; m++) {
    printf("%6d", tab->map[m]);
  }
  printf("\n");

  /* Reference index value. */
  printf("      crval: %p\n", (void *)tab->crval);
  printf("            ");
  for (m = 0; m < tab->M; m++) {
    printf("  %- 11.5g", tab->crval[m]);
  }
  printf("\n");

  /* Index vectors. */
  printf("      index: %p\n", (void *)tab->index);
  for (m = 0; m < tab->M; m++) {
    printf("   index[%d]: %p", m, (void *)tab->index[m]);
    if (tab->index[m]) {
      for (k = 0; k < tab->K[m]; k++) {
        if (k%5 == 0) {
          printf("\n            ");
        }
        printf("  %- 11.5g", tab->index[m][k]);
d585 27
a611 2
    }
  }
d613 3
a615 107
  /* Coordinate array. */
  printf("      coord: %p\n", (void *)tab->coord);
  dp = tab->coord;
  for (n = 0; n < tab->nc; n++) {
    /* Array index. */
    j = n;
    cp = text;
    for (m = 0; m < tab->M; m++) {
      nd = (tab->K[m] < 10) ? 1 : 2;
      sprintf(cp, ",%*d", nd, j % tab->K[m] + 1);
      j /= tab->K[m];
      cp += strlen(cp);
    }

    printf("             (*%s)", text);
    for (m = 0; m < tab->M; m++) {
      printf("  %- 11.5g", *(dp++));
    }
    printf("\n");
  }

  printf("         nc: %d\n", tab->nc);

  if (tab->sense == 0x0) {
    printf("      sense: (nil)\n");
  } else {
    printf("      sense: %p\n", (void *)tab->sense);
    printf("            ");
    for (m = 0; m < tab->M; m++) {
      printf("%6d", tab->sense[m]);
    }
    printf("\n");
  }

  if (tab->p0 == 0x0) {
    printf("         p0: (nil)\n");
  } else {
    printf("         p0: %p\n", (void *)tab->p0);
    printf("            ");
    for (m = 0; m < tab->M; m++) {
      printf("%6d", tab->p0[m]);
    }
    printf("\n");
  }

  if (tab->delta == 0x0) {
    printf("      delta: (nil)\n");
  } else {
    printf("      delta: %p\n", (void *)tab->delta);
    printf("            ");
    for (m = 0; m < tab->M; m++) {
      printf("  %- 11.5g", tab->delta[m]);
    }
    printf("\n");
  }

  printf("    extrema: %p\n", (void *)tab->extrema);
  dp = tab->extrema;
  for (n = 0; n < tab->nc/tab->K[0]; n++) {
    /* Array index. */
    j = n;
    cp = text;
    *cp = '\0';
    for (m = 1; m < tab->M; m++) {
      nd = (tab->K[m] < 10) ? 1 : 2;
      sprintf(cp, ",%*d", nd, j % tab->K[m] + 1);
      j /= tab->K[m];
      cp += strlen(cp);
    }

    printf("             (*,*%s)", text);
    for (m = 0; m < 2*tab->M; m++) {
      if (m == tab->M) printf("->  ");
      printf("  %- 11.5g", *(dp++));
    }
    printf("\n");
  }

  /* Memory management. */
  printf("     m_flag: %d\n", tab->m_flag);
  printf("        m_M: %d\n", tab->m_M);
  printf("        m_N: %d\n", tab->m_N);

  printf("        m_K: %p", (void *)tab->m_K);
  if (tab->m_K == tab->K) printf("  (= K)");
  printf("\n");

  printf("      m_map: %p", (void *)tab->m_map);
  if (tab->m_map == tab->map) printf("  (= map)");
  printf("\n");

  printf("    m_crval: %p", (void *)tab->m_crval);
  if (tab->m_crval == tab->crval) printf("  (= crval)");
  printf("\n");

  printf("    m_index: %p", (void *)tab->m_index);
  if (tab->m_index == tab->index) printf("  (= index)");
  printf("\n");
  for (m = 0; m < tab->M; m++) {
    printf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]);
    if (tab->m_indxs[m] == tab->index[m]) printf("  (= index[%d])", m);
    printf("\n");
  }

  printf("    m_coord: %p", (void *)tab->m_coord);
  if (tab->m_coord == tab->coord) printf("  (= coord)");
  printf("\n");
d617 1
a617 1
  return 0;
d625 2
a626 2
  int i, ic, k, *Km, m, M, ne;
  double *dcrd, *dmax, *dmin, *Psi;
d628 1
a628 1
  if (tab == 0x0) return 1;
d630 2
a631 13
  /* Check the number of tabular coordinate axes. */
  if ((M = tab->M) < 1) {
    return 3;
  }

  /* Check the axis lengths. */
  if (!tab->K) {
    return 2;
  }

  tab->nc = 1;
  for (m = 0; m < M; m++) {
    if (tab->K[m] < 1) {
d633 1
a633 1
    }
d635 4
a638 15
    /* Number of coordinate vectors in the coordinate array. */
    tab->nc *= tab->K[m];
  }

  /* Check that the map vector is sensible. */
  if (!tab->map) {
    return 2;
  }

  for (m = 0; m < M; m++) {
    i = tab->map[m];
    if (i < 0) {
      return 3;
    }
  }
d640 5
a644 12
  /* Check memory allocation for the remaining vectors. */
  if (!tab->crval || !tab->index || !tab->coord) {
    return 2;
  }

  /* Take memory if signalled to by wcstab(). */
  for (m = 0; m < tab->m_M; m++) {
    if (tab->m_indxs[m] == (double *)0x1 &&
      (tab->m_indxs[m] = tab->index[m])) {
      tab->m_flag = TABSET;
    }
  }
d646 3
a648 13
  if (tab->m_coord == (double *)0x1 &&
    (tab->m_coord = tab->coord)) {
    tab->m_flag = TABSET;
  }


  /* Allocate memory for work vectors. */
  if (tab->flag != TABSET || tab->set_M < M) {
    /* Free memory that may have been allocated previously. */
    if (tab->sense)   free(tab->sense);
    if (tab->p0)      free(tab->p0);
    if (tab->delta)   free(tab->delta);
    if (tab->extrema) free(tab->extrema);
d650 2
a651 2
    /* Allocate memory for internal arrays. */
    if (!(tab->sense = calloc(M, sizeof(int)))) {
d653 8
a660 1
    }
d662 2
a663 2
    if (!(tab->p0 = calloc(M, sizeof(int)))) {
      free(tab->sense);
d665 14
a678 1
    }
a679 5
    if (!(tab->delta = calloc(M, sizeof(double)))) {
      free(tab->sense);
      free(tab->p0);
      return 2;
    }
d681 31
a711 7
    ne = M * tab->nc * 2 / tab->K[0];
    if (!(tab->extrema = calloc(ne, sizeof(double)))) {
      free(tab->sense);
      free(tab->p0);
      free(tab->delta);
      return 2;
    }
d713 2
a714 2
    tab->set_M = M;
  }
d716 4
a719 9
  /* Check that the index vectors are monotonic. */
  Km = tab->K;
  for (m = 0; m < M; m++, Km++) {
    tab->sense[m] = 0;

    if (*Km > 1) {
      if ((Psi = tab->index[m]) == 0) {
        /* Default indexing. */
        tab->sense[m] = 1;
d721 17
a737 12
      } else {
        for (k = 0; k < *Km-1; k++) {
          switch (tab->sense[m]) {
          case 0:
            if (Psi[k] < Psi[k+1]) {
              /* Monotonic increasing. */
              tab->sense[m] = 1;
            } else if (Psi[k] > Psi[k+1]) {
              /* Monotonic decreasing. */
              tab->sense[m] = -1;
            }
            break;
d739 10
a748 10
          case 1:
            if (Psi[k] > Psi[k+1]) {
              /* Should be monotonic increasing. */
              free(tab->sense);
              free(tab->p0);
              free(tab->delta);
              free(tab->extrema);
              return 3;
            }
            break;
d750 11
a760 8
          case -1:
            if (Psi[k] < Psi[k+1]) {
              /* Should be monotonic decreasing. */
              free(tab->sense);
              free(tab->p0);
              free(tab->delta);
              free(tab->extrema);
              return 3;
d762 1
a762 23
            break;
          }
        }
      }

      if (tab->sense[m] == 0) {
        free(tab->sense);
        free(tab->p0);
        free(tab->delta);
        free(tab->extrema);
        return 3;
      }
    }
  }

  /* Deduce the extremal values of the coordinate elements in each row. */
  dcrd = tab->coord;
  dmin = tab->extrema;
  dmax = tab->extrema + M;
  for (ic = 0; ic < tab->nc; ic += tab->K[0]) {
    for (m = 0; m < M; m++, dcrd++) {
      *(dmax+m) = *(dmin+m) = *dcrd;
    }
d764 15
a778 1
    for (i = 1; i < tab->K[0]; i++) {
d780 8
a787 2
        if (*(dmax+m) < *dcrd) *(dmax+m) = *dcrd;
        if (*(dmin+m) > *dcrd) *(dmin+m) = *dcrd;
a788 1
    }
d790 3
a792 3
    dmin += 2*M;
    dmax += 2*M;
  }
d794 1
a794 1
  tab->flag = TABSET;
d796 1
a796 1
  return 0;
d802 6
a807 6
  struct tabprm *tab,
  int ncoord,
  int nelem,
  const double x[],
  double world[],
  int stat[])
d810 25
a834 29
  int i, iv, k, *Km, m, M, n, nv, offset, p0, status;
  double *coord, *Psi, psi_m, upsilon, wgt;
  register int *statp;
  register const double *xp;
  register double *wp;

  /* Initialize if required. */
  if (tab == 0x0) return 1;
  if (tab->flag != TABSET) {
    if ((status = tabset(tab))) return status;
  }

  /* This is used a lot. */
  M = tab->M;

  status = 0;
  xp = x;
  wp = world;
  statp = stat;
  for (n = 0; n < ncoord; n++) {
    /* Determine the indexes. */
    Km = tab->K;
    for (m = 0; m < M; m++, Km++) {
      i = tab->map[m];
      psi_m = *(xp+i) + tab->crval[m];

      if ((Psi = tab->index[m]) == 0) {
        /* Default indexing is simple. */
        upsilon = psi_m;
d836 2
a837 4
      } else {
        if (*Km == 1) {
          /* Index vector is degenerate. */
          if (Psi[0]-0.5 <= psi_m && psi_m <= Psi[0]+0.5) {
a838 5
          } else {
            *statp = 1;
            status = 4;
            goto next;
          }
d840 10
a849 27
        } else {
          /* Interpolate in the indexing vector. */
          if (tab->sense[m] == 1) {
            /* Monotonic increasing index values. */
            if (psi_m < Psi[0]) {
              if (Psi[0] - 0.5*(Psi[1]-Psi[0]) <= psi_m) {
                /* Allow minor extrapolation. */
                k = 0;

              } else {
                /* Index is out of range. */
                *statp = 1;
                status = 4;
                goto next;
              }

            } else if (Psi[*Km-1] < psi_m) {
              if (psi_m <= Psi[*Km-1] + 0.5*(Psi[*Km-1]-Psi[*Km-2])) {
                /* Allow minor extrapolation. */
                k = *Km - 2;

              } else {
                /* Index is out of range. */
                *statp = 1;
                status = 4;
                goto next;
              }
d852 83
a934 11
              for (k = 0; k < *Km-1; k++) {
                if (psi_m < Psi[k]) {
                  continue;
                }
                if (Psi[k] == psi_m && psi_m < Psi[k+1]) {
                  break;
                }
                if (Psi[k] < psi_m && psi_m <= Psi[k+1]) {
                  break;
                }
              }
d936 1
d938 6
a943 40
          } else {
            /* Monotonic decreasing index values. */
            if (psi_m > Psi[0]) {
              if (Psi[0] + 0.5*(Psi[0]-Psi[1]) >= psi_m) {
                /* Allow minor extrapolation. */
                k = 0;

              } else {
                /* Index is out of range. */
                *statp = 1;
                status = 4;
                goto next;
              }

            } else if (psi_m < Psi[*Km-1]) {
              if (Psi[*Km-1] - 0.5*(Psi[*Km-2]-Psi[*Km-1]) <= psi_m) {
                /* Allow minor extrapolation. */
                k = *Km - 2;

              } else {
                /* Index is out of range. */
                *statp = 1;
                status = 4;
                goto next;
              }

            } else {
              for (k = 0; k < *Km-1; k++) {
                if (psi_m > Psi[k]) {
                  continue;
                }
                if (Psi[k] == psi_m && psi_m > Psi[k+1]) {
                  break;
                }
                if (Psi[k] > psi_m && psi_m >= Psi[k+1]) {
                  break;
                }
              }
            }
          }
d945 4
a948 3
          upsilon = k + (psi_m - Psi[k]) / (Psi[k+1] - Psi[k]);
        }
      }
d950 7
a956 5
      if (upsilon < -0.5 || upsilon > *Km - 0.5) {
        /* Index out of range. */
        *statp = 1;
        status = 4;
        goto next;
a958 4
      /* Fiducial array indices and fractional offset. */
      p0 = (int)floor(upsilon);
      tab->p0[m] = p0;
      tab->delta[m] = upsilon - p0;
d960 5
a964 6
      if (p0 == -1) {
       tab->p0[m] += 1;
       tab->delta[m] -= 1.0;
      } else if (p0 == *Km-1 && *Km > 1) {
       tab->p0[m] -= 1;
       tab->delta[m] += 1.0;
a965 1
    }
d967 16
d984 1
a984 6
    /* Now interpolate in the coordinate array; the M-dimensional linear  */
    /* interpolation algorithm is described in Sect. 3.4 of WCS Paper IV. */
    for (m = 0; m < M; m++) {
     i = tab->map[m];
     *(wp+i) = 0.0;
    }
d986 6
a991 18
    /* Loop over the 2^M vertices surrounding P. */
    nv = 1 << M;
    for (iv = 0; iv < nv; iv++) {
      /* Locate vertex in the coordinate array and compute its weight. */
      offset = 0;
      wgt = 1.0;
      for (m = M-1; m >= 0; m--) {
        offset *= tab->K[m];
        offset += tab->p0[m];
        if (iv & (1 << m)) {
          if (tab->K[m] > 1) offset++;
          wgt *= tab->delta[m];
        } else {
          wgt *= 1.0 - tab->delta[m];
        }
      }

      if (wgt == 0.0) continue;
d993 1
a993 5
      /* Add the contribution from this vertex to each element. */
      coord = tab->coord + offset*M;
      for (m = 0; m < M; m++) {
        i = tab->map[m];
        *(wp+i) += *(coord++) * wgt;
d996 1
a996 4
      if (wgt == 1.0) break;
    }

    *statp = 0;
d999 4
a1002 4
    xp += nelem;
    wp += nelem;
    statp++;
  }
d1004 1
a1004 1
  return status;
d1010 6
a1015 6
  struct tabprm* tab,
  int ncoord,
  int nelem,
  const double world[],
  double x[],
  int stat[])
d1018 75
a1092 61
  int tabedge(struct tabprm *);
  int tabrow(struct tabprm *, const double *);
  int tabvox(struct tabprm *, const double *, int, unsigned int *);

  int edge, i, ic, k, *Km, M, m, n, status;
  double *Psi, psi_m, upsilon;
  register int *statp;
  register const double *wp;
  register double *xp;

  /* Initialize if required. */
  if (tab == 0x0) return 1;
  if (tab->flag != TABSET) {
    if ((status = tabset(tab))) return status;
  }

  /* This is used a lot. */
  M = tab->M;


  status = 0;
  wp = world;
  xp = x;
  statp = stat;
  for (n = 0; n < ncoord; n++) {
    /* Locate this coordinate in the coordinate array. */
    edge = 0;
    for (m = 0; m < M; m++) {
      tab->p0[m] = 0;
    }

    for (ic = 0; ic < tab->nc; ic++) {
      if (tab->p0[0] == 0) {
        /* New row, could it contain a solution? */
        if (edge || tabrow(tab, wp)) {
          /* No, skip it. */
          ic += tab->K[0] - 1;
          tab->p0[1]++;
          edge = tabedge(tab);
          continue;
        }
      }

      if (M == 1) {
        /* Deal with the one-dimensional case separately. */
        if (*wp == tab->coord[0]) {
          tab->p0[0] = 0;
          tab->delta[0] = 0.0;
          break;

        } else if (ic < tab->nc - 1) {
          if (((tab->coord[ic] <= *wp && *wp <= tab->coord[ic+1]) ||
               (tab->coord[ic] >= *wp && *wp >= tab->coord[ic+1])) &&
               (tab->index[0] == 0 ||
                tab->index[0][ic] != tab->index[0][ic+1])) {
            tab->p0[0] = ic;
            tab->delta[0] = (*wp - tab->coord[ic]) /
                            (tab->coord[ic+1] - tab->coord[ic]);
            break;
          }
        }
d1094 4
d1099 8
a1106 32
        /* Multi-dimensional tables are much harder. */
        if (!edge && tabvox(tab, wp, 0, 0) == 0) {
          /* Found a solution. */
          break;
        }

        /* Next voxel. */
        tab->p0[0]++;
        edge = tabedge(tab);
      }
    }


    if (ic == tab->nc) {
      /* Coordinate not found. */
      *statp = 1;
      status = 5;
    } else {
      /* Determine the intermediate world coordinates. */
      Km = tab->K;
      for (m = 0; m < M; m++, Km++) {
        upsilon = tab->p0[m] + tab->delta[m];
        if (upsilon < -0.5 || upsilon > *Km - 0.5) {
          /* Index out of range. */
          *statp = 1;
          status = 5;

        } else {
          /* Do inverse lookup of the index vector. */
          if ((Psi = tab->index[m]) == 0) {
            /* Default indexing. */
            psi_m = upsilon;
a1107 4
          } else {
            if (*Km == 1) {
              /* Degenerate index vector. */
              psi_m = Psi[0];
d1109 20
a1128 5
              k = (int)upsilon;
              psi_m = Psi[k];
              if (k < *Km-1) {
                psi_m += (upsilon - k) * (Psi[k+1] - Psi[k]);
              }
d1130 2
a1131 5
          }

          i = tab->map[m];
          xp[i] = psi_m - tab->crval[m];
        }
a1132 2
      *statp = 0;
    }
d1134 4
a1137 4
    wp += nelem;
    xp += nelem;
    statp++;
  }
d1139 1
a1139 1
  return status;
d1149 1
a1149 1
  int edge, *Km, m;
d1151 11
a1161 11
  edge = 0;
  Km = tab->K;
  for (m = 0; m < tab->M; m++, Km++) {
    if (tab->p0[m] == *Km) {
      tab->p0[m] = 0;
      tab->p0[m+1]++;
    } else if (tab->p0[m] == *Km - 1 && *Km > 1) {
      /* Edge effects? */
      edge = 1;
    }
  }
d1163 1
a1163 1
  return edge;
d1174 43
a1216 37
  int iv, M, m, nv, offset;
  unsigned int eq, et, gt, lt;
  const double tol = 1.0e-10;
  double *cp, w;

  M = tab->M;

  /* Could the coordinate lie somewhere along this row of voxels? */
  lt = 0;
  gt = 0;
  eq = 0;
  nv = 1 << M;
  for (iv = 0; iv < nv; iv++) {
    /* Find the extrema at this end of the row. */
    offset = 0;
    for (m = M-1; m > 0; m--) {
      offset *= tab->K[m];
      offset += tab->p0[m];
      if (iv & (1 << m)) {
        if (tab->K[m] > 1) offset++;
      }
    }

    offset *= 2;
    offset += tab->p0[0];
    if (iv & 1 && tab->K[0] > 1) offset++;

    et = 0;
    cp = tab->extrema + offset*M;
    for (m = 0; m < M; m++, cp++) {
      w = wp[tab->map[m]];
      if (fabs(*cp - w) < tol) {
        et |= (1 << m);
      } else if (*cp < w) {
        lt |= (1 << m);
      } else if (*cp > w) {
        gt |= (1 << m);
a1217 1
    }
d1219 5
a1223 2
    if (et == nv-1) {
      /* Solution found in a corner. */
d1225 1
a1225 9
    }

    eq |= et;
  }

  if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
    /* A solution could lie within this row of voxels. */
    return 0;
  }
d1227 2
a1228 2
  /* No solution in this row. */
  return 1;
d1241 4
a1244 26
  int i, iv, jv, M, m, nv, offset;
  unsigned int eq, et, gt, lt, vox2[16];
  const double tol = 1.0e-10;
  double coord[16], *cp, dv, w, wgt;

  M = tab->M;

  dv = 1.0;
  for (i = 0; i < level; i++) {
    dv /= 2.0;
  }

  /* Could the coordinate lie within this voxel? */
  lt = 0;
  gt = 0;
  eq = 0;
  nv = 1 << M;
  for (iv = 0; iv < nv; iv++) {
    /* Compute the coordinates of this corner of the voxel. */
    for (m = 0; m < M; m++) {
      coord[m] = 0.0;
      tab->delta[m] = level ? dv*vox[m] : 0.0;
      if (iv & (1 << m)) {
        tab->delta[m] += dv;
      }
    }
d1246 1
a1246 13
    for (jv = 0; jv < nv; jv++) {
      offset = 0;
      wgt = 1.0;
      for (m = M-1; m >= 0; m--) {
        offset *= tab->K[m];
        offset += tab->p0[m];
        if (jv & (1 << m)) {
          if (tab->K[m] > 1) offset++;
          wgt *= tab->delta[m];
        } else {
          wgt *= 1.0 - tab->delta[m];
        }
      }
d1248 4
a1251 1
      if (wgt == 0.0) continue;
d1253 7
a1259 1
      cp = tab->coord + offset*M;
d1261 20
a1280 2
        coord[m] += *(cp++) * wgt;
      }
d1282 1
a1282 2
      if (wgt == 1.0) break;
    }
d1284 4
a1287 12
    /* Coordinate elements are minimal or maximal in a corner. */
    et = 0;
    for (m = 0; m < M; m++) {
      w = wp[tab->map[m]];
      if (fabs(coord[m] - w) < tol) {
        et |= (1 << m);
      } else if (coord[m] < w) {
        lt |= (1 << m);
      } else if (coord[m] > w) {
        gt |= (1 << m);
      }
    }
d1289 1
a1289 16
    if (et == nv-1) {
      /* Solution found in a corner. */
      return 0;
    }

    eq |= et;
  }

  if ((lt | eq) == nv-1 && (gt | eq) == nv-1) {
    /* The coordinate could lie within this voxel, but does it? */

    if (level == 31) {
      /* Stop the recursion. */
      dv /= 2.0;
      for (m = 0; m < M; m++) {
        tab->delta[m] = dv * (2.0*vox[m] + 1.0);
d1292 2
a1293 5
      return 0;
    }

    /* Subdivide and try again. */
    for (iv = 0; iv < nv; iv++) {
d1295 39
a1333 5
        vox2[m] = level ? 2*vox[m] : 0;
        if (iv & (1 << m)) {
          vox2[m]++;
        }
      }
d1335 3
a1337 2
      if (tabvox(tab, wp, level+1, vox2) == 0) {
        return 0;
d1339 1
a1339 2
    }
  }
d1341 2
a1342 2
  /* No solution in this voxel. */
  return 1;
@


4.2
log
@WCSLIB 4.2: the incorrect indexing variable, m instead of i, was used for
tab->crval[] in tabx2s() and tabs2x(); allow extrapolation by half a cell
at either end of the index and coordinate tables.
@
text
@d2 30
a31 29
*
*   WCSLIB 4.2 - an implementation of the FITS WCS standard.
*   Copyright (C) 1995-2005, Mark Calabretta
*
*   WCSLIB is free software; you can redistribute it and/or modify it under
*   the terms of the GNU General Public License as published by the Free
*   Software Foundation; either version 2 of the License, or (at your option)
*   any later version.
*
*   WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
*   WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
*   FOR A PARTICULAR PURPOSE.  See the GNU General Public License for more
*   details.
*
*   You should have received a copy of the GNU General Public License along
*   with WCSLIB; if not, write to the Free Software Foundation, Inc.,
*   59 Temple Place, Suite 330, Boston, MA  02111-1307, USA
*
*   Correspondence concerning WCSLIB may be directed to:
*      Internet email: mcalabre@@atnf.csiro.au
*      Postal address: Dr. Mark Calabretta
*                      Australia Telescope National Facility, CSIRO
*                      PO Box 76
*                      Epping NSW 1710
*                      AUSTRALIA
*
*   Author: Mark Calabretta, Australia Telescope National Facility
*   http://www.atnf.csiro.au/~mcalabre/index.html
*   $Id: tab.c,v 4.1 2005/08/31 03:52:31 cal103 Exp cal103 $
d239 1
a239 1
         if (dp = tab->index[m]) {
d297 1
a297 1
      if (tab->m_K = tab->K) {
d303 1
a303 1
      if (tab->m_map = tab->map) {
d309 1
a309 1
      if (tab->m_crval = tab->crval) {
d315 1
a315 1
      if (tab->m_index = tab->index) {
d322 1
a322 1
         if (tab->m_indxs[m] = tab->index[m]) {
d329 1
a329 1
      if (tab->m_coord = tab->coord) {
d354 1
a354 1
   if (status = tabini(alloc, M, tabsrc->K, tabdst)) {
d366 1
a366 1
      if (srcp = tabsrc->index[m]) {
d471 1
a471 1
   printf("          K: 0x%x\n", (int)tab->K);
d479 1
a479 1
   printf("        map: 0x%x\n", (int)tab->map);
d487 1
a487 1
   printf("      crval: 0x%x\n", (int)tab->crval);
d495 1
a495 1
   printf("      index: 0x%x\n", (int)tab->index);
d497 1
a497 1
      printf("   index[%d]: 0x%x", m, (int)tab->index[m]);
d510 1
a510 1
   printf("      coord: 0x%x\n", (int)tab->coord);
d533 1
a533 1
      printf("      sense: (null)\n");
d535 1
a535 1
      printf("      sense: 0x%x\n", (int)tab->sense);
d544 1
a544 1
      printf("         p0: (null)\n");
d546 1
a546 1
      printf("         p0: 0x%x\n", (int)tab->p0);
d555 1
a555 1
      printf("      delta: (null)\n");
d557 1
a557 1
      printf("      delta: 0x%x\n", (int)tab->delta);
d565 1
a565 1
   printf("    extrema: 0x%x\n", (int)tab->extrema);
d592 1
a592 1
   printf("        m_K: 0x%x", (int)tab->m_K);
d596 1
a596 1
   printf("      m_map: 0x%x", (int)tab->m_map);
d600 1
a600 1
   printf("    m_crval: 0x%x", (int)tab->m_crval);
d604 1
a604 1
   printf("    m_index: 0x%x", (int)tab->m_index);
d608 1
a608 1
      printf(" m_indxs[%d]: 0x%x", m, (int)tab->m_indxs[m]);
d613 1
a613 1
   printf("    m_coord: 0x%x", (int)tab->m_coord);
d819 1
a819 1
      if (status = tabset(tab)) return status;
d1031 1
a1031 1
      if (status = tabset(tab)) return status;
@


4.2.1.1
log
@WCSLIB 4.2 development branch.
@
text
@d3 1
a3 1
*   WCSLIB 4.3 - an implementation of the FITS WCS standard.
d30 1
a30 1
*   $Id: tab.c,v 4.2 2005/09/22 08:59:02 cal103 Exp cal103 $
@


4.2.1.2
log
@In tabprt(), use the "%p" printf conversion specifier to print addresses
rather than casting the pointer to int and using "#x".  The latter does not
work on 64-bit machines where sizeof(int) != sizeof(void*).
@
text
@d4 1
a4 1
*   Copyright (C) 1995-2006, Mark Calabretta
d30 1
a30 1
*   $Id: tab.c,v 4.2.1.1 2005/12/05 02:39:43 cal103 Exp cal103 $
d470 1
a470 1
   printf("          K: %p\n", tab->K);
d478 1
a478 1
   printf("        map: %p\n", tab->map);
d486 1
a486 1
   printf("      crval: %p\n", tab->crval);
d494 1
a494 1
   printf("      index: %p\n", tab->index);
d496 1
a496 1
      printf("   index[%d]: %p", m, tab->index[m]);
d509 1
a509 1
   printf("      coord: %p\n", tab->coord);
d534 1
a534 1
      printf("      sense: %p\n", tab->sense);
d545 1
a545 1
      printf("         p0: %p\n", tab->p0);
d556 1
a556 1
      printf("      delta: %p\n", tab->delta);
d564 1
a564 1
   printf("    extrema: %p\n", tab->extrema);
d591 1
a591 1
   printf("        m_K: %p", tab->m_K);
d595 1
a595 1
   printf("      m_map: %p", tab->m_map);
d599 1
a599 1
   printf("    m_crval: %p", tab->m_crval);
d603 1
a603 1
   printf("    m_index: %p", tab->m_index);
d607 1
a607 1
      printf(" m_indxs[%d]: %p", m, tab->m_indxs[m]);
d612 1
a612 1
   printf("    m_coord: %p", tab->m_coord);
@


4.2.1.3
log
@In tabprt(), the "%p" printf conversion specifier prints "(nil)" for a null-
pointer so follow suit.
@
text
@d30 1
a30 1
*   $Id: tab.c,v 4.2.1.2 2006/06/01 07:34:15 cal103 Exp cal103 $
d532 1
a532 1
      printf("      sense: (nil)\n");
d543 1
a543 1
      printf("         p0: (nil)\n");
d554 1
a554 1
      printf("      delta: (nil)\n");
@


4.2.1.4
log
@Parenthesised assignments used as truth values.
@
text
@d4 1
a4 1
*   Copyright (C) 1995-2007, Mark Calabretta
d30 1
a30 1
*   $Id: tab.c,v 4.2.1.3 2006/06/01 07:47:53 cal103 Exp cal103 $
d238 1
a238 1
         if ((dp = tab->index[m])) {
d296 1
a296 1
      if ((tab->m_K = tab->K)) {
d302 1
a302 1
      if ((tab->m_map = tab->map)) {
d308 1
a308 1
      if ((tab->m_crval = tab->crval)) {
d314 1
a314 1
      if ((tab->m_index = tab->index)) {
d321 1
a321 1
         if ((tab->m_indxs[m] = tab->index[m])) {
d328 1
a328 1
      if ((tab->m_coord = tab->coord)) {
d353 1
a353 1
   if ((status = tabini(alloc, M, tabsrc->K, tabdst))) {
d365 1
a365 1
      if ((srcp = tabsrc->index[m])) {
d818 1
a818 1
      if ((status = tabset(tab))) return status;
d1030 1
a1030 1
      if ((status = tabset(tab))) return status;
@


4.2.1.5
log
@Cast pointers to (void *) for %p formatting by printf() to avert a compiler
warning.
@
text
@d30 1
a30 1
*   $Id: tab.c,v 4.2.1.4 2007/06/29 00:43:47 cal103 Exp cal103 $
d470 1
a470 1
   printf("          K: %p\n", (void *)tab->K);
d478 1
a478 1
   printf("        map: %p\n", (void *)tab->map);
d486 1
a486 1
   printf("      crval: %p\n", (void *)tab->crval);
d494 1
a494 1
   printf("      index: %p\n", (void *)tab->index);
d496 1
a496 1
      printf("   index[%d]: %p", m, (void *)tab->index[m]);
d509 1
a509 1
   printf("      coord: %p\n", (void *)tab->coord);
d534 1
a534 1
      printf("      sense: %p\n", (void *)tab->sense);
d545 1
a545 1
      printf("         p0: %p\n", (void *)tab->p0);
d556 1
a556 1
      printf("      delta: %p\n", (void *)tab->delta);
d564 1
a564 1
   printf("    extrema: %p\n", (void *)tab->extrema);
d591 1
a591 1
   printf("        m_K: %p", (void *)tab->m_K);
d595 1
a595 1
   printf("      m_map: %p", (void *)tab->m_map);
d599 1
a599 1
   printf("    m_crval: %p", (void *)tab->m_crval);
d603 1
a603 1
   printf("    m_index: %p", (void *)tab->m_index);
d607 1
a607 1
      printf(" m_indxs[%d]: %p", m, (void *)tab->m_indxs[m]);
d612 1
a612 1
   printf("    m_coord: %p", (void *)tab->m_coord);
@


4.2.1.6
log
@Switched to LGPL 3.0.
@
text
@d2 29
a30 30

    WCSLIB 4.3 - an implementation of the FITS WCS standard.
    Copyright (C) 1995-2007, Mark Calabretta

    This file is part of WCSLIB.

    WCSLIB is free software: you can redistribute it and/or modify it under
    the terms of the GNU Lesser General Public License as published by the
    Free Software Foundation, either version 3 of the License, or (at your
    option) any later version.

    WCSLIB is distributed in the hope that it will be useful, but WITHOUT ANY
    WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS
    FOR A PARTICULAR PURPOSE.  See the GNU Lesser General Public License for
    more details.

    You should have received a copy of the GNU Lesser General Public License
    along with WCSLIB.  If not, see <http://www.gnu.org/licenses/>.

    Correspondence concerning WCSLIB may be directed to:
       Internet email: mcalabre@@atnf.csiro.au
       Postal address: Dr. Mark Calabretta
                       Australia Telescope National Facility, CSIRO
                       PO Box 76
                       Epping NSW 1710
                       AUSTRALIA

    Author: Mark Calabretta, Australia Telescope National Facility
    http://www.atnf.csiro.au/~mcalabre/index.html
    $Id: tab.c,v 4.2.1.5 2007/07/11 02:01:30 cal103 Exp cal103 $
@


4.1
log
@WCSLIB 4.1: set tab_errmsg[0] to "success"; removed support for K&R C; allow
K == 0 and also K[m] == 0 in tabini() for wcstab(); use tabprm.m_indxs[] for
fine-grained bookkeeping of the index arrays and allocate each individually,
also used by wcstab() to send signals to tabset() to take memory by setting
the address to 0x1; fixed memory management in tabini(), tabfree() and
tabset() for arrays allocated by tabset(); new function tabmem() takes user-
allocated memory; report parameters and intermediate variables to an extra
decimal place in tabprt(); tabprt() prints the array index for the index
and coord vectors, and also prints m_indxs[]; do more checks on memory
allocation in tabset(); recognize tabprm.index[] == 0x0 as default indexing
in tabset(), tabx2s() and tabs2x().
@
text
@d3 1
a3 1
*   WCSLIB 4.1 - an implementation of the FITS WCS standard.
d30 1
a30 1
*   $Id: tab.c,v 4.0 2005/02/06 11:47:16 cal103 Exp cal103 $
d833 1
a833 1
         psi_m = *(xp+i) + tab->crval[i];
d842 2
a843 2
               if (psi_m == Psi[0]) {
                  upsilon = Psi[0];
d854 11
a864 6
                  if (psi_m < Psi[0] || psi_m > Psi[*Km-1]) {
                     /* Index is out of range. */
                     *statp = 1;
                     status = 4;
                     goto next;
                  }
d866 10
a875 3
                  for (k = 0; k < *Km-1; k++) {
                     if (psi_m < Psi[k]) {
                        continue;
d877 12
a888 5
                     if (Psi[k] == psi_m && psi_m < Psi[k+1]) {
                        break;
                     }
                     if (Psi[k] < psi_m && psi_m <= Psi[k+1]) {
                        break;
d894 11
a904 6
                  if (psi_m > Psi[0] || psi_m < Psi[*Km-1]) {
                     /* Index is out of range. */
                     *statp = 1;
                     status = 4;
                     goto next;
                  }
d906 10
a915 3
                  for (k = 0; k < *Km-1; k++) {
                     if (psi_m > Psi[k]) {
                        continue;
d917 12
a928 5
                     if (Psi[k] == psi_m && psi_m > Psi[k+1]) {
                        break;
                     }
                     if (Psi[k] > psi_m && psi_m >= Psi[k+1]) {
                        break;
d937 1
a937 1
         if (upsilon < 0.0 || upsilon > (double)(*Km-1)) {
d949 4
a952 1
         if (p0 == *Km-1 && *Km > 1) {
d954 1
a954 1
           tab->delta[m] = 1.0;
d1102 1
a1102 1
            if (upsilon < 0.0 || upsilon > (double)(*Km-1)) {
d1124 1
d1126 2
a1127 3
                  i = tab->map[m];
                  xp[i] = psi_m - tab->crval[i];
               }
@


4.0
log
@WCSLIB 4.0: initial revision.
@
text
@d3 1
a3 1
*   WCSLIB 4.0 - an implementation of the FITS WCS standard.
d30 1
a30 1
*   $Id$
d36 1
d45 1
a45 1
   0,
d54 1
a54 5
int tabini(alloc, M, K, tab)

int alloc, M;
const int K[];
struct tabprm *tab;
d57 1
a57 1
   int k, l, m, N;
d60 1
a60 1
   if (tab == 0) return 1;
d62 1
a62 1
   if (M <= 0 || K == 0) {
d67 10
a76 4
   N = M;
   for (m = 0; m < M; m++) {
      N *= K[m];
   }
d78 3
a80 2
   if (N <= 0) {
      return 3;
d89 22
a110 5
      tab->m_K     = 0;
      tab->m_map   = 0;
      tab->m_crval = 0;
      tab->m_index = 0;
      tab->m_coord = 0;
d113 1
d116 5
a120 5
       tab->K == 0 ||
       tab->map == 0 ||
       tab->crval == 0 ||
       tab->index == 0 ||
       tab->coord == 0) {
d128 1
a128 1
      if (alloc || tab->K == 0) {
a139 1
            tab->m_N = N;
d144 1
a144 1
      if (alloc || tab->map == 0) {
a155 1
            tab->m_N = N;
d160 1
a160 1
      if (alloc || tab->crval == 0) {
a171 1
            tab->m_N = N;
d176 1
a176 1
      if (alloc || tab->index == 0) {
d186 4
a189 4
            l = 0;
            for (m = 0; m < M; m++) {
               l += K[m];
            }
d191 1
a191 1
            if (!(tab->index[0] = calloc(l, sizeof(double)))) {
d195 10
a204 3
            for (m = 0; m < M; m++) {
               if (m) {
                  tab->index[m] = tab->index[m-1] + K[m-1];
a206 5

            tab->m_flag = TABSET;
            tab->m_M = M;
            tab->m_N = N;
            tab->m_index = tab->index;
d210 1
a210 1
      if (alloc || tab->coord == 0) {
d215 1
a215 1
         } else {
a227 14
   /* Free memory allocated by tabset(). */
   if (tab->flag == TABSET) {
      if (tab->sense)   free(tab->sense);
      if (tab->p0)      free(tab->p0);
      if (tab->delta)   free(tab->delta);
      if (tab->extrema) free(tab->extrema);
   }

   tab->sense   = 0;
   tab->p0      = 0;
   tab->delta   = 0;
   tab->extrema = 0;
   tab->set_M   = 0;

d231 1
a231 1
   /* Copy K[] and initialize map[] and crval[]. */
a232 1
      tab->K[m] = K[m];
a234 1
   }
d236 9
a244 5
   /* Initialize the index vectors. */
   for (m = 0; m < M; m++) {
      dp = tab->index[m];
      for (k = 0; k < K[m]; k++) {
         *(dp++) = k;
d258 1
a258 1
int tabcpy(alloc, tabsrc, tabdst)
d260 81
a340 3
int alloc;
const struct tabprm *tabsrc;
struct tabprm *tabdst;
d346 1
a346 1
   if (tabsrc == 0) return 1;
d365 5
a369 5
      srcp = tabsrc->index[m];
      dstp = tabdst->index[m];

      for (k = 0; k < tabsrc->K[m]; k++) {
         *(dstp++) = *(srcp++);
d384 1
a384 1
int tabfree(tab)
d386 2
a387 1
struct tabprm *tab;
d389 1
a389 2
{
   if (tab == 0) return 1;
d392 7
d401 5
a405 5
         if (tab->K     == tab->m_K)     tab->K = 0;
         if (tab->map   == tab->m_map)   tab->map = 0;
         if (tab->crval == tab->m_crval) tab->crval = 0;
         if (tab->index == tab->m_index) tab->index = 0;
         if (tab->coord == tab->m_coord) tab->coord = 0;
d410 1
d412 3
a414 1
            free(tab->m_index[0]);
d416 1
d418 1
a420 10
   }

   tab->m_flag  = 0;
   tab->m_M     = 0;
   tab->m_N     = 0;
   tab->m_K     = 0;
   tab->m_map   = 0;
   tab->m_crval = 0;
   tab->m_index = 0;
   tab->m_coord = 0;
d422 1
a422 3

   /* Free memory allocated by tabset(). */
   if (tab->flag == TABSET) {
d429 14
a442 4
   tab->sense   = 0;
   tab->p0      = 0;
   tab->delta   = 0;
   tab->extrema = 0;
d452 1
a452 3
int tabprt(tab)

const struct tabprm *tab;
d455 2
a456 1
   int k, m, n, N;
d459 1
a459 1
   if (tab == 0) return 1;
d489 1
a489 1
      printf("  %- 11.4g", tab->crval[m]);
d497 6
a502 3
      for (k = 0; k < tab->K[m]; k++) {
         if (k%5 == 0) {
            printf("\n            ");
d504 1
a504 1
         printf("  %- 11.4g", tab->index[m][k]);
a508 2
   N = tab->M * tab->nc;

a509 1
   printf("            ");
d511 14
a524 5
   for (n = 0; n < N;) {
/* Should print the array index. */
      printf("             (%d)", n);
      for (m = 0; m < tab->M; m++, n++) {
         printf("  %- 11.4g", *(dp++));
a527 1
   printf("\n");
d531 1
a531 1
   if (tab->sense == 0) {
d542 1
a542 1
   if (tab->p0 == 0) {
d553 1
a553 1
   if (tab->delta == 0) {
d559 1
a559 1
         printf("  %- 11.4g", tab->delta[m]);
a563 1
   N *= 2/tab->K[0];
a564 1
   printf("            ");
d566 16
a581 5
   for (n = 0; n < N;) {
/* Should print the array index. */
      printf("             (%d)", n);
      for (m = 0; m < tab->M; m++, n++) {
         printf("  %- 11.4g", *(dp++));
a584 1
   printf("\n");
d590 1
d594 1
d598 1
d602 1
d606 6
d621 1
a621 3
int tabset(tab)

struct tabprm *tab;
d627 1
a627 3
   if (tab == 0) return 1;

   M = tab->M;
d630 1
a630 1
   if (M < 1) {
d635 4
d650 4
d661 19
d682 5
a686 7
      if (tab->flag == TABSET) {
         /* Free memory that may have been allocated previously. */
         if (tab->sense)   free(tab->sense);
         if (tab->p0)      free(tab->p0);
         if (tab->delta)   free(tab->delta);
         if (tab->extrema) free(tab->extrema);
      }
d721 16
a736 1
         Psi = tab->index[m];
d738 10
a747 10
         for (k = 0; k < *Km-1; k++) {
            if (tab->sense[m] == 0) {
               if (Psi[k] < Psi[k+1]) {
                  /* Monotonic increasing. */
                  tab->sense[m] = 1;
               } else if (Psi[k] > Psi[k+1]) {
                  /* Monotonic decreasing. */
                  tab->sense[m] = -1;
               }
            }
d749 10
a758 17
            if (tab->sense[m] == 1) {
               if (Psi[k] > Psi[k+1]) {
                  /* Should be monotonic increasing. */
                  free(tab->sense);
                  free(tab->p0);
                  free(tab->delta);
                  free(tab->extrema);
                  return 3;
               }
            } else if (tab->sense[m] == -1) {
               if (Psi[k] < Psi[k+1]) {
                  /* Should be monotonic decreasing. */
                  free(tab->sense);
                  free(tab->p0);
                  free(tab->delta);
                  free(tab->extrema);
                  return 3;
d800 7
a806 7
int tabx2s(tab, ncoord, nelem, x, world, stat)

struct tabprm *tab;
int ncoord, nelem;
const double x[];
double world[];
int stat[];
d816 1
a816 1
   if (tab == 0) return 1;
d830 1
a830 1
      Km  = tab->K;
d835 3
a837 10
         Psi = tab->index[m];
         if (*Km == 1) {
            /* Index vector is degenerate. */
            if (psi_m == Psi[0]) {
               upsilon = Psi[0];
            } else {
               *statp = 1;
               status = 4;
               goto next;
            }
d840 5
a844 5
            /* Interpolate in the indexing vector. */
            if (tab->sense[m] == 1) {
               /* Monotonic increasing index values. */
               if (psi_m < Psi[0] || psi_m > Psi[*Km-1]) {
                  /* Index is out of range. */
d850 9
a858 3
               for (k = 0; k < *Km-1; k++) {
                  if (psi_m < Psi[k]) {
                     continue;
d860 11
a870 2
                  if (Psi[k] == psi_m && psi_m < Psi[k+1]) {
                     break;
d872 8
a879 2
                  if (Psi[k] < psi_m && psi_m <= Psi[k+1]) {
                     break;
a880 1
               }
d882 11
a892 7
            } else {
               /* Monotonic decreasing index values. */
               if (psi_m > Psi[0] || psi_m < Psi[*Km-1]) {
                  /* Index is out of range. */
                  *statp = 1;
                  status = 4;
                  goto next;
d895 1
a895 11
               for (k = 0; k < *Km-1; k++) {
                  if (psi_m > Psi[k]) {
                     continue;
                  }
                  if (Psi[k] == psi_m && psi_m > Psi[k+1]) {
                     break;
                  }
                  if (Psi[k] > psi_m && psi_m >= Psi[k+1]) {
                     break;
                  }
               }
a896 2

            upsilon = k + (psi_m - Psi[k]) / (Psi[k+1] - Psi[k]);
d900 1
a900 1
            /* Index out of range (shouldn't be possible). */
d967 7
a973 7
int tabs2x(tab, ncoord, nelem, world, x, stat)

struct tabprm* tab;
int ncoord, nelem;
const double world[];
double x[];
int stat[];
d987 1
a987 1
   if (tab == 0) return 1;
d1029 2
a1030 1
                     tab->index[0][ic] != tab->index[0][ic+1]) {
d1068 4
a1071 4
               Psi = tab->index[m];
               if (*Km == 1) {
                  /* Degenerate index vector. */
                  psi_m = Psi[0];
d1073 13
a1085 2
                  k = (int)upsilon;
                  psi_m = Psi[k] + (upsilon - k) * (Psi[k+1] - Psi[k]);
a1086 3

               i = tab->map[m];
               xp[i] = psi_m - tab->crval[i];
d1097 1
a1097 1
   return 0;
@


0.0
log
@Empty revision
@
text
@d1 1136
@
