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.12.23.27;	author cal103;	state Exp;
branches
	4.2.1.1;
next	4.1;

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

4.0
date	2005.02.04.06.08.26;	author cal103;	state Exp;
branches;
next	3.6;

3.6
date	2004.08.25.05.18.22;	author cal103;	state Exp;
branches;
next	3.5;

3.5
date	2004.06.28.04.03.12;	author mcalabre;	state Exp;
branches;
next	3.4;

3.4
date	2004.02.11.00.15.03;	author mcalabre;	state Exp;
branches;
next	3.3;

3.3
date	2003.10.22.07.16.43;	author mcalabre;	state Exp;
branches;
next	3.2;

3.2
date	2003.09.09.04.34.11;	author mcalabre;	state Exp;
branches;
next	3.1;

3.1
date	2003.04.28.03.50.41;	author mcalabre;	state Exp;
branches;
next	3.0;

3.0
date	2003.04.01.04.10.53;	author mcalabre;	state Exp;
branches;
next	2.23;

2.23
date	2002.04.03.01.25.29;	author mcalabre;	state Exp;
branches;
next	2.22;

2.22
date	2002.04.03.00.07.18;	author mcalabre;	state Exp;
branches;
next	2.21;

2.21
date	2001.09.05.04.38.38;	author mcalabre;	state Exp;
branches;
next	2.20;

2.20
date	2001.06.18.05.03.38;	author mcalabre;	state Exp;
branches;
next	2.19;

2.19
date	2001.02.19.00.39.48;	author mcalabre;	state Exp;
branches;
next	2.18;

2.18
date	2000.12.05.03.43.53;	author mcalabre;	state Exp;
branches;
next	2.17;

2.17
date	2000.09.07.22.49.26;	author mcalabre;	state Exp;
branches;
next	2.16;

2.16
date	2000.05.10.04.44.05;	author mcalabre;	state Exp;
branches;
next	2.15;

2.15
date	2000.04.04.03.41.37;	author mcalabre;	state Exp;
branches;
next	2.14;

2.14
date	99.12.14.01.09.28;	author mcalabre;	state Exp;
branches;
next	2.13;

2.13
date	99.12.13.07.37.56;	author mcalabre;	state Exp;
branches;
next	2.12;

2.12
date	99.11.19.00.51.18;	author mcalabre;	state Exp;
branches;
next	2.11;

2.11
date	98.07.20.04.09.19;	author mcalabre;	state Exp;
branches;
next	2.10;

2.10
date	98.02.25.07.05.50;	author mcalabre;	state Exp;
branches;
next	2.9;

2.9
date	98.02.25.06.36.55;	author mcalabre;	state Exp;
branches;
next	2.8;

2.8
date	98.01.30.00.26.02;	author mcalabre;	state Exp;
branches;
next	2.7;

2.7
date	97.02.19.03.22.04;	author mcalabre;	state Exp;
branches;
next	2.6;

2.6
date	97.01.02.22.09.49;	author mcalabre;	state Exp;
branches;
next	2.5;

2.5
date	96.09.10.06.37.10;	author mcalabre;	state Exp;
branches;
next	2.4;

2.4
date	96.05.24.07.25.36;	author mcalabre;	state Exp;
branches;
next	2.3;

2.3
date	96.05.07.20.10.15;	author mcalabre;	state Exp;
branches;
next	2.2;

2.2
date	95.11.16.04.48.51;	author mcalabre;	state Exp;
branches;
next	2.1;

2.1
date	95.11.09.03.29.00;	author mcalabre;	state Exp;
branches;
next	2.0;

2.0
date	95.09.11.08.44.44;	author mcalabre;	state Exp;
branches;
next	1.2;

1.2
date	95.09.11.04.38.08;	author mcalabre;	state Exp;
branches;
next	1.1;

1.1
date	95.01.31.03.20.27;	author mcalabre;	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	2005.12.05.02.43.23;	author cal103;	state Exp;
branches;
next	4.2.1.3;

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

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

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

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

4.2.1.7
date	2007.07.27.04.32.14;	author cal103;	state Exp;
branches;
next	4.2.1.8;

4.2.1.8
date	2007.07.27.08.43.10;	author cal103;	state Exp;
branches;
next	4.2.1.9;

4.2.1.9
date	2007.08.02.04.28.32;	author cal103;	state Exp;
branches;
next	4.2.1.10;

4.2.1.10
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	2008.07.17.05.52.08;	author cal103;	state Exp;
branches;
next	4.3.1.3;

4.3.1.3
date	2008.09.09.01.57.09;	author cal103;	state Exp;
branches;
next	4.3.1.4;

4.3.1.4
date	2009.07.22.04.28.39;	author cal103;	state Exp;
branches;
next	4.3.1.5;

4.3.1.5
date	2009.07.28.07.45.25;	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	2009.09.03.02.13.43;	author cal103;	state Exp;
branches;
next	4.4.1.3;

4.4.1.3
date	2010.01.19.03.42.50;	author cal103;	state Exp;
branches;
next	4.4.1.4;

4.4.1.4
date	2010.07.07.13.26.46;	author cal103;	state Exp;
branches;
next	4.4.1.5;

4.4.1.5
date	2010.07.09.07.58.02;	author cal103;	state Exp;
branches;
next	;

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

4.5.1.2
date	2010.09.23.01.32.16;	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.01.27.00.27.00;	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.06.03.02.05.54;	author cal103;	state Exp;
branches;
next	4.7.1.3;

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

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

4.7.1.5
date	2011.08.10.05.14.13;	author cal103;	state Exp;
branches;
next	4.7.1.6;

4.7.1.6
date	2011.08.10.05.31.04;	author cal103;	state Exp;
branches;
next	4.7.1.7;

4.7.1.7
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.10.27;	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.9.1.2;

4.9.1.2
date	2012.01.31.23.56.50;	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.43.15;	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.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.18.1.2;

4.18.1.2
date	2013.09.29.10.22.01;	author mcalabre;	state Exp;
branches;
next	;

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

4.19.1.2
date	2013.12.10.23.07.23;	author mcalabre;	state Exp;
branches;
next	4.19.1.3;

4.19.1.3
date	2013.12.17.14.55.10;	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.26.56;	author mcalabre;	state Exp;
branches;
next	4.22.1.3;

4.22.1.3
date	2014.05.10.14.29.04;	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.11.05.11;	author mcalabre;	state Exp;
branches;
next	;

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

4.24.1.2
date	2014.12.09.04.29.22;	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.08.20.35;	author mcalabre;	state Exp;
branches;
next	4.25.1.4;

4.25.1.4
date	2015.04.03.02.17.33;	author mcalabre;	state Exp;
branches;
next	4.25.1.5;

4.25.1.5
date	2015.04.03.04.02.46;	author mcalabre;	state Exp;
branches;
next	4.25.1.6;

4.25.1.6
date	2015.04.05.06.00.29;	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.1.1.2;

5.1.1.2
date	2015.04.10.15.47.22;	author mcalabre;	state Exp;
branches;
next	5.1.1.3;

5.1.1.3
date	2015.04.13.08.35.43;	author mcalabre;	state Exp;
branches;
next	5.1.1.4;

5.1.1.4
date	2015.04.15.09.08.37;	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.16.08.20.39;	author mcalabre;	state Exp;
branches;
next	5.6.1.3;

5.6.1.3
date	2015.06.16.13.34.46;	author mcalabre;	state Exp;
branches;
next	5.6.1.4;

5.6.1.4
date	2015.06.16.14.16.20;	author mcalabre;	state Exp;
branches;
next	;

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

5.7.1.2
date	2015.07.08.07.09.44;	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.18.08.21.34;	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	2017.12.04.04.42.57;	author mcalabre;	state Exp;
branches;
next	5.17.1.3;

5.17.1.3
date	2017.12.05.07.43.16;	author mcalabre;	state Exp;
branches;
next	5.17.1.4;

5.17.1.4
date	2017.12.05.21.15.54;	author mcalabre;	state Exp;
branches;
next	5.17.1.5;

5.17.1.5
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.24.13.58.12;	author mcalabre;	state Exp;
branches;
next	5.18.1.3;

5.18.1.3
date	2018.07.26.14.35.45;	author mcalabre;	state Exp;
branches;
next	;

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

5.19.1.2
date	2018.10.05.04.44.10;	author mcalabre;	state Exp;
branches;
next	;

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

5.20.1.2
date	2018.10.19.06.05.05;	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.34.14;	author mcalabre;	state Exp;
branches;
next	6.2.1.4;

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

6.2.1.5
date	2019.07.09.11.52.02;	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.14.40;	author mcalabre;	state Exp;
branches;
next	6.4.1.3;

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

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

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

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

7.1.1.2
date	2020.02.26.08.15.14;	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.11.36.54;	author mcalabre;	state Exp;
branches;
next	7.3.1.5;

7.3.1.5
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.4.1.2;

7.4.1.2
date	2021.02.22.07.23.26;	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.09.03.55.45;	author mcalabre;	state Exp;
branches;
next	7.5.1.3;

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

7.5.1.4
date	2021.04.10.14.22.30;	author mcalabre;	state Exp;
branches;
next	7.5.1.5;

7.5.1.5
date	2021.04.13.09.29.31;	author mcalabre;	state Exp;
branches;
next	;

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

7.6.1.2
date	2021.07.01.08.33.22;	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.16.08.14.29;	author mcalabre;	state Exp;
branches;
next	7.7.1.3;

7.7.1.3
date	2022.03.22.05.15.25;	author mcalabre;	state Exp;
branches;
next	7.7.1.4;

7.7.1.4
date	2022.03.22.06.12.49;	author mcalabre;	state Exp;
branches;
next	7.7.1.5;

7.7.1.5
date	2022.03.25.05.39.35;	author mcalabre;	state Exp;
branches;
next	7.7.1.6;

7.7.1.6
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.8.1.2;

7.8.1.2
date	2022.03.25.14.58.54;	author mcalabre;	state Exp;
branches;
next	;

7.9.1.1
date	2022.03.25.15.16.40;	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.43.48;	author mcalabre;	state Exp;
branches;
next	;

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

7.11.1.2
date	2022.09.03.08.06.19;	author mcalabre;	state Exp;
branches;
next	7.11.1.3;

7.11.1.3
date	2022.09.08.04.03.12;	author mcalabre;	state Exp;
branches;
next	7.11.1.4;

7.11.1.4
date	2022.09.09.02.12.08;	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.03.05.37.07;	author mcalabre;	state Exp;
branches;
next	7.13.1.3;

7.13.1.3
date	2023.06.15.04.17.19;	author mcalabre;	state Exp;
branches;
next	7.13.1.4;

7.13.1.4
date	2023.07.01.06.07.46;	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.41.57;	author mcalabre;	state Exp;
branches;
next	8.2.1.3;

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

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

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

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

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

8.2.1.8
date	2024.05.10.14.38.48;	author mcalabre;	state Exp;
branches;
next	8.2.1.9;

8.2.1.9
date	2024.05.13.05.09.41;	author mcalabre;	state Exp;
branches;
next	8.2.1.10;

8.2.1.10
date	2024.05.13.14.33.51;	author mcalabre;	state Exp;
branches;
next	8.2.1.11;

8.2.1.11
date	2024.05.13.16.07.43;	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.05.20.08.57.49;	author mcalabre;	state Exp;
branches;
next	8.3.1.3;

8.3.1.3
date	2024.07.09.09.12.30;	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.05.08.43.34;	author mcalabre;	state Exp;
branches;
next	8.6.1.3;

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

8.6.1.4
date	2026.04.12.11.41.38;	author mcalabre;	state Exp;
branches;
next	8.6.1.5;

8.6.1.5
date	2026.04.21.08.36.22;	author mcalabre;	state Exp;
branches;
next	8.6.1.6;

8.6.1.6
date	2026.04.22.15.11.39;	author mcalabre;	state Exp;
branches;
next	8.6.1.7;

8.6.1.7
date	2026.05.11.11.27.06;	author mcalabre;	state Exp;
branches;
next	;


desc
@High-level driver routines for WCS coordinate transformations.
@


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: wcs.c,v 8.6.1.7 2026/05/11 11:27:06 mcalabre Exp mcalabre $
*===========================================================================*/

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

#include "wcserr.h"
#include "wcsmath.h"
#include "wcslimits.h"
#include "wcsprintf.h"
#include "wcstrig.h"
#include "wcsunits.h"
#include "wcsutil.h"
#include "wtbarr.h"
#include "lin.h"
#include "dis.h"
#include "log.h"
#include "spc.h"
#include "prj.h"
#include "sph.h"
#include "cel.h"
#include "tab.h"
#include "wcs.h"

// Maximum number of PVi_ma and PSi_ma keywords.  May be changed by wcsnpv().
int NPVMAX = 64;
int NPSMAX =  8;

// Maximum number of DPja or DQia keywords.  May be changed by disndp().
int NDPMAX = 256;

// Map status return value to message.
const char *wcs_errmsg[] = {
  "Success",
  "Null wcsprm pointer passed",
  "Memory allocation failed",
  "Linear transformation matrix is singular",
  "Inconsistent or unrecognized coordinate axis type",
  "Invalid parameter value",
  "Unrecognized coordinate transformation parameter",
  "Ill-conditioned coordinate transformation parameter",
  "One or more of the pixel coordinates were invalid",
  "One or more of the world coordinates were invalid",
  "Invalid world coordinate",
  "No solution found in the specified interval",
  "Invalid subimage specification",
  "Non-separable subimage coordinate system",
  "wcsprm struct is unset, use wcsset()"};

// Map error returns for lower-level routines.
const int wcs_linerr[] = {
  WCSERR_SUCCESS,		//  0: LINERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: LINERR_NULL_POINTER
  WCSERR_MEMORY,		//  2: LINERR_MEMORY
  WCSERR_SINGULAR_MTX,		//  3: LINERR_SINGULAR_MTX
  WCSERR_BAD_PARAM,		//  4: LINERR_DISTORT_INIT
  WCSERR_BAD_PIX,		//  5: LINERR_DISTORT
  WCSERR_BAD_WORLD		//  6: LINERR_DEDISTORT
};

const int wcs_logerr[] = {
  WCSERR_SUCCESS,		//  0: LOGERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: LOGERR_NULL_POINTER
  WCSERR_BAD_PARAM,		//  2: LOGERR_BAD_LOG_REF_VAL
  WCSERR_BAD_PIX,		//  3: LOGERR_BAD_X
  WCSERR_BAD_WORLD		//  4: LOGERR_BAD_WORLD
};

const int wcs_spcerr[] = {
				// -1: SPCERR_NO_CHANGE
  WCSERR_SUCCESS,		//  0: SPCERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: SPCERR_NULL_POINTER
  WCSERR_BAD_PARAM,		//  2: SPCERR_BAD_SPEC_PARAMS
  WCSERR_BAD_PIX,		//  3: SPCERR_BAD_X
  WCSERR_BAD_WORLD		//  4: SPCERR_BAD_SPEC
};

const int wcs_celerr[] = {
  WCSERR_SUCCESS,		//  0: CELERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: CELERR_NULL_POINTER
  WCSERR_BAD_PARAM,		//  2: CELERR_BAD_PARAM
  WCSERR_BAD_COORD_TRANS,	//  3: CELERR_BAD_COORD_TRANS
  WCSERR_ILL_COORD_TRANS,	//  4: CELERR_ILL_COORD_TRANS
  WCSERR_BAD_PIX,		//  5: CELERR_BAD_PIX
  WCSERR_BAD_WORLD		//  6: CELERR_BAD_WORLD
};

const int wcs_taberr[] = {
  WCSERR_SUCCESS,		//  0: TABERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: TABERR_NULL_POINTER
  WCSERR_MEMORY,		//  2: TABERR_MEMORY
  WCSERR_BAD_PARAM,		//  3: TABERR_BAD_PARAMS
  WCSERR_BAD_PIX,		//  4: TABERR_BAD_X
  WCSERR_BAD_WORLD		//  5: TABERR_BAD_WORLD
};

static const int WCSSET = 137;

// Internal helper functions, not for general use.
static int wcs_types(struct wcsprm *);
static int time_type(const char *);
static int time_code(const char *ctype, int nc);
static int wcs_units(struct wcsprm *);
static int wcs_chksum(const struct wcsprm *wcs);
static int wcs_fletcher32(int chksum, const void *data, size_t len);

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

#ifndef signbit
#define signbit(X) ((X) < 0.0 ? 1 : 0)
#endif

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

int wcsnpv(int npvmax) { if (npvmax >= 0) NPVMAX = npvmax; return NPVMAX; }
int wcsnps(int npsmax) { if (npsmax >= 0) NPSMAX = npsmax; return NPSMAX; }

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

int wcsini(int alloc, int naxis, struct wcsprm *wcs)

{
  return wcsinit(alloc, naxis, wcs, -1, -1, -1);
}

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

int wcsinit(
  int alloc,
  int naxis,
  struct wcsprm *wcs,
  int npvmax,
  int npsmax,
  int ndpmax)

{
  static const char *function = "wcsinit";

  int status;

  // Check inputs.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (npvmax < 0) npvmax = wcsnpv(-1);
  if (npsmax < 0) npsmax = wcsnps(-1);


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

  // ...and also in the contained structs in case we have to return due to
  // an error before they can be initialized by their specialized routines,
  // since wcsperr() assumes their wcserr pointers are valid.
  if (wcs->flag == -1) {
    wcs->lin.err = 0x0;
    wcs->cel.err = 0x0;
    wcs->spc.err = 0x0;
  }
  wcserr_clear(&(wcs->lin.err));
  wcserr_clear(&(wcs->cel.err));
  wcserr_clear(&(wcs->spc.err));


  // Initialize pointers.
  if (wcs->flag == -1 || wcs->m_flag != WCSSET) {
    if (wcs->flag == -1) {
      wcs->tab   = 0x0;
      wcs->types = 0x0;
      wcs->lin.flag = -1;
    }

    // Initialize memory management.
    wcs->m_flag  = 0;
    wcs->m_naxis = 0;
    wcs->m_crpix = 0x0;
    wcs->m_pc    = 0x0;
    wcs->m_cdelt = 0x0;
    wcs->m_crval = 0x0;
    wcs->m_cunit = 0x0;
    wcs->m_ctype = 0x0;
    wcs->m_pv    = 0x0;
    wcs->m_ps    = 0x0;
    wcs->m_cd    = 0x0;
    wcs->m_crota = 0x0;
    wcs->m_colax = 0x0;
    wcs->m_cname = 0x0;
    wcs->m_crder = 0x0;
    wcs->m_csyer = 0x0;
    wcs->m_czphs = 0x0;
    wcs->m_cperi = 0x0;
    wcs->m_aux   = 0x0;
    wcs->m_tab   = 0x0;
    wcs->m_wtb   = 0x0;
  }

  // Sanity check on naxis.
  if (naxis < 0) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
      "naxis must not be negative (got %d)", naxis);
  }

  if (NAXMAX < naxis) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
      "naxis exceeds %d (got %d)", NAXMAX, naxis);
  }

  // Balm for clang-tidy.
  size_t naxszt = naxis;


  // Allocate memory for arrays if required.
  if (alloc ||
     wcs->crpix == 0x0 ||
     wcs->pc    == 0x0 ||
     wcs->cdelt == 0x0 ||
     wcs->crval == 0x0 ||
     wcs->cunit == 0x0 ||
     wcs->ctype == 0x0 ||
     (npvmax && wcs->pv == 0x0) ||
     (npsmax && wcs->ps == 0x0) ||
     wcs->cd    == 0x0 ||
     wcs->crota == 0x0 ||
     wcs->colax == 0x0 ||
     wcs->cname == 0x0 ||
     wcs->crder == 0x0 ||
     wcs->csyer == 0x0 ||
     wcs->czphs == 0x0 ||
     wcs->cperi == 0x0) {

    // Was sufficient allocated previously?
    if (wcs->m_flag == WCSSET &&
       (wcs->m_naxis < naxis  ||
        wcs->npvmax  < npvmax ||
        wcs->npsmax  < npsmax)) {
      // No, free it.
      wcsfree(wcs);
    }

    if (alloc || wcs->crpix == 0x0) {
      if (wcs->m_crpix) {
        // In case the caller fiddled with it.
        wcs->crpix = wcs->m_crpix;

      } else {
        if ((wcs->crpix = calloc(naxszt, sizeof(double))) == 0x0) {
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crpix = wcs->crpix;
      }
    }

    if (alloc || wcs->pc == 0x0) {
      if (wcs->m_pc) {
        // In case the caller fiddled with it.
        wcs->pc = wcs->m_pc;

      } else {
        if ((wcs->pc = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_pc    = wcs->pc;
      }
    }

    if (alloc || wcs->cdelt == 0x0) {
      if (wcs->m_cdelt) {
        // In case the caller fiddled with it.
        wcs->cdelt = wcs->m_cdelt;

      } else {
        if ((wcs->cdelt = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cdelt = wcs->cdelt;
      }
    }

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

      } else {
        if ((wcs->crval = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crval = wcs->crval;
      }
    }

    if (alloc || wcs->cunit == 0x0) {
      if (wcs->m_cunit) {
        // In case the caller fiddled with it.
        wcs->cunit = wcs->m_cunit;

      } else {
        if ((wcs->cunit = calloc(naxszt, sizeof(char [72]))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cunit = wcs->cunit;
      }
    }

    if (alloc || wcs->ctype == 0x0) {
      if (wcs->m_ctype) {
        // In case the caller fiddled with it.
        wcs->ctype = wcs->m_ctype;

      } else {
        if ((wcs->ctype = calloc(naxszt, sizeof(char [72]))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_ctype = wcs->ctype;
      }
    }

    if (alloc || wcs->pv == 0x0) {
      if (wcs->m_pv) {
        // In case the caller fiddled with it.
        wcs->pv = wcs->m_pv;

      } else {
        if (npvmax) {
          if ((wcs->pv = calloc(npvmax, sizeof(struct pvcard))) == 0x0) {
            wcsfree(wcs);
            return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
          }
        } else {
          wcs->pv = 0x0;
        }

        wcs->npvmax  = npvmax;

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_pv    = wcs->pv;
      }
    }

    if (alloc || wcs->ps == 0x0) {
      if (wcs->m_ps) {
        // In case the caller fiddled with it.
        wcs->ps = wcs->m_ps;

      } else {
        if (npsmax) {
          if ((wcs->ps = calloc(npsmax, sizeof(struct pscard))) == 0x0) {
            wcsfree(wcs);
            return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
          }
        } else {
          wcs->ps = 0x0;
        }

        wcs->npsmax  = npsmax;

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_ps    = wcs->ps;
      }
    }

    if (alloc || wcs->cd == 0x0) {
      if (wcs->m_cd) {
        // In case the caller fiddled with it.
        wcs->cd = wcs->m_cd;

      } else {
        if ((wcs->cd = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cd    = wcs->cd;
      }
    }

    if (alloc || wcs->crota == 0x0) {
      if (wcs->m_crota) {
        // In case the caller fiddled with it.
        wcs->crota = wcs->m_crota;

      } else {
        if ((wcs->crota = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crota = wcs->crota;
      }
    }

    if (alloc || wcs->colax == 0x0) {
      if (wcs->m_colax) {
        // In case the caller fiddled with it.
        wcs->colax = wcs->m_colax;

      } else {
        if ((wcs->colax = calloc(naxszt, sizeof(int))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_colax = wcs->colax;
      }
    }

    if (alloc || wcs->cname == 0x0) {
      if (wcs->m_cname) {
        // In case the caller fiddled with it.
        wcs->cname = wcs->m_cname;

      } else {
        if ((wcs->cname = calloc(naxszt, sizeof(char [72]))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cname = wcs->cname;
      }
    }

    if (alloc || wcs->crder == 0x0) {
      if (wcs->m_crder) {
        // In case the caller fiddled with it.
        wcs->crder = wcs->m_crder;

      } else {
        if ((wcs->crder = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crder = wcs->crder;
      }
    }

    if (alloc || wcs->csyer == 0x0) {
      if (wcs->m_csyer) {
        // In case the caller fiddled with it.
        wcs->csyer = wcs->m_csyer;

      } else {
        if ((wcs->csyer = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_csyer = wcs->csyer;
      }
    }

    if (alloc || wcs->czphs == 0x0) {
      if (wcs->m_czphs) {
        // In case the caller fiddled with it.
        wcs->czphs = wcs->m_czphs;

      } else {
        if ((wcs->czphs = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_czphs = wcs->czphs;
      }
    }

    if (alloc || wcs->cperi == 0x0) {
      if (wcs->m_cperi) {
        // In case the caller fiddled with it.
        wcs->cperi = wcs->m_cperi;

      } else {
        if ((wcs->cperi = calloc(naxszt, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cperi = wcs->cperi;
      }
    }
  }


  wcs->naxis = naxis;

  // Set defaults for the linear transformation.
  wcs->lin.crpix = wcs->crpix;
  wcs->lin.pc    = wcs->pc;
  wcs->lin.cdelt = wcs->cdelt;
  if ((status = lininit(0, naxis, &(wcs->lin), ndpmax))) {
    return wcserr_set(WCS_ERRMSG(wcs_linerr[status]));
  }


  // CRVALia defaults to 0.0.
  for (int i = 0; i < naxis; i++) {
    wcs->crval[i] = 0.0;
  }


  // CUNITia and CTYPEia are blank by default.
  for (int i = 0; i < naxis; i++) {
    memset(wcs->cunit[i], 0, 72);
    memset(wcs->ctype[i], 0, 72);
  }


  // Set defaults for the celestial transformation parameters.
  wcs->lonpole = UNDEFINED;
  wcs->latpole = +90.0;

  // Set defaults for the spectral transformation parameters.
  wcs->restfrq = 0.0;
  wcs->restwav = 0.0;

  // Default parameter values.
  wcs->npv = 0;
  for (int k = 0; k < wcs->npvmax; k++) {
    wcs->pv[k].i = 0;
    wcs->pv[k].m = 0;
    wcs->pv[k].value = 0.0;
  }

  wcs->nps = 0;
  for (int k = 0; k < wcs->npsmax; k++) {
    wcs->ps[k].i = 0;
    wcs->ps[k].m = 0;
    memset(wcs->ps[k].value, 0, 72);
  }

  // Defaults for alternate linear transformations.
  double *cd = wcs->cd;
  for (int i = 0; i < naxis; i++) {
    for (int j = 0; j < naxis; j++) {
      *(cd++) = 0.0;
    }
  }
  for (int i = 0; i < naxis; i++) {
    wcs->crota[i] = 0.0;
  }
  wcs->altlin = 0;
  wcs->velref = 0;

  // Defaults for auxiliary coordinate system information.
  memset(wcs->alt, 0, 4);
  wcs->alt[0] = ' ';
  wcs->colnum = 0;

  for (int i = 0; i < naxis; i++) {
    wcs->colax[i] = 0;
    memset(wcs->cname[i], 0, 72);
    wcs->crder[i] = UNDEFINED;
    wcs->csyer[i] = UNDEFINED;
    wcs->czphs[i] = UNDEFINED;
    wcs->cperi[i] = UNDEFINED;
  }

  memset(wcs->wcsname, 0, 72);

  memset(wcs->timesys,  0, 72);
  memset(wcs->trefpos,  0, 72);
  memset(wcs->trefdir,  0, 72);
  memset(wcs->plephem,  0, 72);

  memset(wcs->timeunit, 0, 72);
  memset(wcs->dateref,  0, 72);
  wcs->mjdref[0]  = UNDEFINED;
  wcs->mjdref[1]  = UNDEFINED;
  wcs->timeoffs   = UNDEFINED;

  memset(wcs->dateobs, 0, 72);
  memset(wcs->datebeg, 0, 72);
  memset(wcs->dateavg, 0, 72);
  memset(wcs->dateend, 0, 72);
  wcs->mjdobs     = UNDEFINED;
  wcs->mjdbeg     = UNDEFINED;
  wcs->mjdavg     = UNDEFINED;
  wcs->mjdend     = UNDEFINED;
  wcs->jepoch     = UNDEFINED;
  wcs->bepoch     = UNDEFINED;
  wcs->tstart     = UNDEFINED;
  wcs->tstop      = UNDEFINED;
  wcs->xposure    = UNDEFINED;
  wcs->telapse    = UNDEFINED;

  wcs->timsyer    = UNDEFINED;
  wcs->timrder    = UNDEFINED;
  wcs->timedel    = UNDEFINED;
  wcs->timepixr   = UNDEFINED;

  wcs->obsgeo[0]  = UNDEFINED;
  wcs->obsgeo[1]  = UNDEFINED;
  wcs->obsgeo[2]  = UNDEFINED;
  wcs->obsgeo[3]  = UNDEFINED;
  wcs->obsgeo[4]  = UNDEFINED;
  wcs->obsgeo[5]  = UNDEFINED;
  memset(wcs->obsorbit, 0, 72);
  memset(wcs->radesys,  0, 72);
  wcs->equinox    = UNDEFINED;
  memset(wcs->specsys,  0, 72);
  memset(wcs->ssysobs,  0, 72);
  wcs->velosys    = UNDEFINED;
  wcs->zsource    = UNDEFINED;
  memset(wcs->ssyssrc,  0, 72);
  wcs->velangl    = UNDEFINED;

  // No additional auxiliary coordinate system information.
  wcs->aux  = 0x0;

  // Tabular parameters.
  wcs->ntab = 0;
  wcs->tab  = 0x0;
  wcs->nwtb = 0;
  wcs->wtb  = 0x0;

  // Reset derived values.
  strncpy(wcs->lngtyp, "    ", 8);
  strncpy(wcs->lattyp, "    ", 8);
  wcs->lng  = -1;
  wcs->lat  = -1;
  wcs->spec = -1;
  wcs->time = -1;
  wcs->cubeface = -1;
  wcs->chksum   =  0;

  celini(&(wcs->cel));
  spcini(&(wcs->spc));

  wcs->flag = 0;

  return 0;
}

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

int wcsauxi(
  int alloc,
  struct wcsprm *wcs)

{
  static const char *function = "wcsauxi";

  // Check inputs.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  // Allocate memory if required.
  if (alloc || wcs->aux == 0x0) {
    if (wcs->m_aux) {
      // In case the caller fiddled with it.
      wcs->aux = wcs->m_aux;

    } else {
      if ((wcs->aux = malloc(sizeof(struct auxprm))) == 0x0) {
        return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      }

      wcs->m_aux = wcs->aux;
    }
  }

  struct auxprm *aux = wcs->aux;
  aux->rsun_ref = UNDEFINED;
  aux->dsun_obs = UNDEFINED;
  aux->crln_obs = UNDEFINED;
  aux->hgln_obs = UNDEFINED;
  aux->hglt_obs = UNDEFINED;

  aux->a_radius = UNDEFINED;
  aux->b_radius = UNDEFINED;
  aux->c_radius = UNDEFINED;
  aux->blon_obs = UNDEFINED;
  aux->blat_obs = UNDEFINED;
  aux->bdis_obs = UNDEFINED;

  return 0;
}

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

int wcssub(
  int alloc,
  const struct wcsprm *wcssrc,
  int *nsub,
  int axes[],
  struct wcsprm *wcsdst)

{
  static const char *function = "wcssub";

  const char *pq = "PQ";
  int  status;

  if (wcssrc == 0x0) return WCSERR_NULL_POINTER;
  if (wcsdst == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcsdst->err);

  // N.B. we do not rely on the wcsprm struct having been set up.
  int naxis;
  if ((naxis = wcssrc->naxis) <= 0) {
    return wcserr_set(WCSERR_SET(WCSERR_MEMORY),
      "naxis must be positive (got %d)", naxis);
  }

  int dummy;
  if (nsub == 0x0) {
    nsub = &dummy;
    *nsub = naxis;
  } else if (*nsub == 0) {
    *nsub = naxis;
  }

  // Allocate enough temporary storage to hold either axes[] xor map[].
  int *itmp;
  int  ntmp = (*nsub <= naxis) ? naxis : *nsub;
  if ((itmp = calloc(ntmp, sizeof(int))) == 0x0) {
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
  }

  int dealloc;
  if ((dealloc = (axes == 0x0))) {
    // Construct an index array.
    if ((axes = calloc(naxis, sizeof(int))) == 0x0) {
      free(itmp);
      return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
    }

    for (int i = 0; i < naxis; i++) {
      axes[i] = i+1;
    }
  }

  // So that we don't try to free uninitialized pointers on cleanup.
  wcsdst->m_aux = 0x0;
  wcsdst->m_tab = 0x0;


  int msub = 0;
  for (int j = 0; j < *nsub; j++) {
    int axis = axes[j];

    if (abs(axis) > 0x1000) {
      // Subimage extraction by type.
      int k = abs(axis) & 0xFF;

      int longitude = k & WCSSUB_LONGITUDE;
      int latitude  = k & WCSSUB_LATITUDE;
      int cubeface  = k & WCSSUB_CUBEFACE;
      int spectral  = k & WCSSUB_SPECTRAL;
      int stokes    = k & WCSSUB_STOKES;
      int time      = k & WCSSUB_TIME;

      int other;
      if ((other = (axis < 0))) {
        longitude = !longitude;
        latitude  = !latitude;
        cubeface  = !cubeface;
        spectral  = !spectral;
        stokes    = !stokes;
        time      = !time;
      }

      for (int i = 0; i < naxis; i++) {
        char ctypei[16];
        strncpy (ctypei, (char *)(wcssrc->ctype + i), 8);
        ctypei[8] = '\0';

        // Find the last non-blank character.
        char *c = ctypei + 8;
        while (c-- > ctypei) {
          if (*c == ' ') *c = '\0';
          if (*c != '\0') break;
        }

        if (
          strcmp(ctypei,   "RA")  == 0 ||
          strcmp(ctypei+1, "LON") == 0 ||
          strcmp(ctypei+2, "LN")  == 0 ||
          strncmp(ctypei,   "RA---", 5) == 0 ||
          strncmp(ctypei+1, "LON-", 4) == 0 ||
          strncmp(ctypei+2, "LN-", 3) == 0) {
          if (!longitude) {
            continue;
          }

        } else if (
          strcmp(ctypei,   "DEC") == 0 ||
          strcmp(ctypei+1, "LAT") == 0 ||
          strcmp(ctypei+2, "LT")  == 0 ||
          strncmp(ctypei,   "DEC--", 5) == 0 ||
          strncmp(ctypei+1, "LAT-", 4) == 0 ||
          strncmp(ctypei+2, "LT-", 3) == 0) {
          if (!latitude) {
            continue;
          }

        } else if ((
          strncmp(ctypei, "FREQ", 4) == 0 ||
          strncmp(ctypei, "ENER", 4) == 0 ||
          strncmp(ctypei, "WAVN", 4) == 0 ||
          strncmp(ctypei, "VRAD", 4) == 0 ||
          strncmp(ctypei, "WAVE", 4) == 0 ||
          strncmp(ctypei, "VOPT", 4) == 0 ||
          strncmp(ctypei, "ZOPT", 4) == 0 ||
          strncmp(ctypei, "AWAV", 4) == 0 ||
          strncmp(ctypei, "VELO", 4) == 0 ||
          strncmp(ctypei, "BETA", 4) == 0) &&
          (ctypei[4] == '\0' || ctypei[4] == '-')) {
          if (!spectral) {
            continue;
          }

        } else if (time_type(ctypei)) {
          if (!time) {
            continue;
          }

        } else if (strcmp(ctypei, "STOKES") == 0) {
          if (!stokes) {
            continue;
          }

        } else if (strcmp(ctypei, "CUBEFACE") == 0) {
          if (!cubeface) {
            continue;
          }

        } else if (!other) {
          continue;
        }

        // This axis is wanted, but has it already been added?
        int k;
        for (k = 0; k < msub; k++) {
          if (itmp[k] == i+1) {
            break;
          }
        }
        if (k == msub) itmp[msub++] = i+1;
      }

    } else if (0 < axis && axis <= naxis) {
      // Check that the requested axis has not already been added.
      int k;
      for (k = 0; k < msub; k++) {
        if (itmp[k] == axis) {
          break;
        }
      }
      if (k == msub) itmp[msub++] = axis;

    } else if (axis == 0) {
      // Graft on a new axis.
      itmp[msub++] = 0;

    } else {
      status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_SUBIMAGE));
      goto cleanup;
    }
  }

  if ((*nsub = msub) == 0) {
    // Zero out this struct.
    status = wcsinit(alloc, 0, wcsdst, 0, 0, 0);
    goto cleanup;
  }

  for (int i = 0; i < *nsub; i++) {
    axes[i] = itmp[i];
  }


  // Construct the inverse axis map (i is 0-relative, j is 1-relative):
  // axes[i] == j means that output axis i+1 comes from input axis j,
  // axes[i] == 0 means to create a new axis,
  //  map[i] == j means that input axis i+1 goes to output axis j,
  //  map[i] == 0 means that input axis i+1 is not used.
  int *map = itmp;
  for (int i = 0; i < naxis; i++) {
    map[i] = 0;
  }

  for (int i = 0; i < *nsub; i++) {
    if (axes[i] > 0) {
      map[axes[i]-1] = i+1;
    }
  }


  // Check that the subimage coordinate system is separable.  First check
  // non-zero, off-diagonal elements of the linear transformation matrix.
  double *dstp;
  const double *srcp = wcssrc->pc;
  for (int i = 0; i < naxis; i++) {
    for (int j = 0; j < naxis; j++) {
      if (*(srcp++) == 0.0 || j == i) continue;

      if ((map[i] == 0) != (map[j] == 0)) {
        status = wcserr_set(WCSERR_SET(WCSERR_NON_SEPARABLE),
          "Non-zero off-diagonal matrix elements excluded from the subimage");
        goto cleanup;
      }
    }
  }

  // Tabular coordinates, if any, will be checked below.

  // Now check for distortions that depend on other axes.  As the disprm
  // struct may not have been initialized, we must parse the dpkey entries.
  int ndpmax = 0;
  for (int m = 0; m < 2; m++) {
    struct disprm *dissrc;
    if (m == 0) {
      dissrc = wcssrc->lin.dispre;
    } else {
      dissrc = wcssrc->lin.disseq;
    }

    int ndp = 0;
    if (dissrc != 0x0) {
      for (int j = 0; j < naxis; j++) {
        if (map[j] == 0) continue;

        // Axis numbers in axmap[] are 0-relative.
        int axmap[NAXMAX];
        for (int jhat = 0; jhat < NAXMAX; jhat++) {
          axmap[jhat] = -1;
        }

        int Nhat = 0;
        struct dpkey *dpsrc = dissrc->dp;
        for (int idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
          // Thorough error checking will be done later by disset().
          if (dpsrc->j != j+1) continue;
          if (dpsrc->field[1] != pq[m]) continue;
          char *fp;
          if ((fp = strchr(dpsrc->field, '.')) == 0x0) continue;
          fp++;

          ndp++;

          if (strcmp(fp, "NAXES") == 0) {
            Nhat = dpkeyi(dpsrc);
          } else if (strncmp(fp, "AXIS.", 5) == 0) {
            int jhat;
            sscanf(fp+5, "%d", &jhat);
            axmap[jhat-1] = dpkeyi(dpsrc) - 1;
          }
        }

        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat) {
          status = wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
            "NAXES was not set (or bad) for %s distortion on axis %d",
            dissrc->dtype[j], j+1);
          goto cleanup;
        }

        for (int jhat = 0; jhat < Nhat; jhat++) {
          if (axmap[jhat] < 0) {
            axmap[jhat] = jhat;

            // Make room for an additional DPja.AXIS.j record.
            ndp++;
          }

          if (map[axmap[jhat]] == 0) {
            // Distortion depends on an axis excluded from the subimage.
            status = wcserr_set(WCSERR_SET(WCSERR_NON_SEPARABLE),
              "Distortion depends on an axis excluded from the subimage.");
            goto cleanup;
          }
        }
      }
    }

    if (ndpmax < ndp) ndpmax = ndp;
  }


  // Number of PVi_ma records in the subimage.
  int npvmax = 0;
  for (int m = 0; m < wcssrc->npv; m++) {
    int i = wcssrc->pv[m].i;
    if (i == 0 || (i > 0 && map[i-1])) {
      npvmax++;
    }
  }

  // Number of PSi_ma records in the subimage.
  int npsmax = 0;
  for (int m = 0; m < wcssrc->nps; m++) {
    int i = wcssrc->ps[m].i;
    if (i > 0 && map[i-1]) {
      npsmax++;
    }
  }

  // Initialize the destination.
  status = wcsinit(alloc, *nsub, wcsdst, npvmax, npsmax, ndpmax);

  for (int m = 0; m < 2; m++) {
    struct disprm *dissrc, *disdst;
    if (m == 0) {
      dissrc = wcssrc->lin.dispre;
      disdst = wcsdst->lin.dispre;
    } else {
      dissrc = wcssrc->lin.disseq;
      disdst = wcsdst->lin.disseq;
    }

    if (dissrc && !disdst) {
      if ((disdst = calloc(1, sizeof(struct disprm))) == 0x0) {
        status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        goto cleanup;
      }

      // Also inits disdst.
      disdst->flag = -1;
      lindist(m+1, &(wcsdst->lin), disdst, ndpmax);
    }
  }

  if (status) {
    goto cleanup;
  }


  // Linear transformation.
  srcp = wcssrc->crpix;
  dstp = wcsdst->crpix;
  for (int j = 0; j < *nsub; j++, dstp++) {
    if (axes[j] > 0) {
      int k = axes[j] - 1;
      *dstp = *(srcp+k);
    }
  }

  srcp = wcssrc->pc;
  dstp = wcsdst->pc;
  for (int i = 0; i < *nsub; i++) {
    for (int j = 0; j < *nsub; j++, dstp++) {
      if (axes[i] > 0 && axes[j] > 0) {
        int k = (axes[i]-1)*naxis + (axes[j]-1);
        *dstp = *(srcp+k);
      }
    }
  }

  srcp = wcssrc->cdelt;
  dstp = wcsdst->cdelt;
  for (int i = 0; i < *nsub; i++, dstp++) {
    if (axes[i] > 0) {
      int k = axes[i] - 1;
      *dstp = *(srcp+k);
    }
  }

  // Coordinate reference value.
  srcp = wcssrc->crval;
  dstp = wcsdst->crval;
  for (int i = 0; i < *nsub; i++, dstp++) {
    if (axes[i] > 0) {
      int k = axes[i] - 1;
      *dstp = *(srcp+k);
    }
  }

  // Coordinate units and type.
  for (int i = 0; i < *nsub; i++) {
    if (axes[i] > 0) {
      int k = axes[i] - 1;
      strncpy(wcsdst->cunit[i], wcssrc->cunit[k], 72);
      strncpy(wcsdst->ctype[i], wcssrc->ctype[k], 72);
    }
  }

  // Celestial and spectral transformation parameters.
  wcsdst->lonpole = wcssrc->lonpole;
  wcsdst->latpole = wcssrc->latpole;
  wcsdst->restfrq = wcssrc->restfrq;
  wcsdst->restwav = wcssrc->restwav;

  // Parameter values.
  int npv = 0;
  for (int m = 0; m < wcssrc->npv; m++) {
    int i = wcssrc->pv[m].i;
    if (i == 0) {
      // i == 0 is a special code that means "the latitude axis".
      wcsdst->pv[npv] = wcssrc->pv[m];
      wcsdst->pv[npv].i = 0;
      npv++;
    } else if (i > 0 && map[i-1]) {
      wcsdst->pv[npv] = wcssrc->pv[m];
      wcsdst->pv[npv].i = map[i-1];
      npv++;
    }
  }
  wcsdst->npv = npv;

  int nps = 0;
  for (int m = 0; m < wcssrc->nps; m++) {
    int i = wcssrc->ps[m].i;
    if (i > 0 && map[i-1]) {
      wcsdst->ps[nps] = wcssrc->ps[m];
      wcsdst->ps[nps].i = map[i-1];
      nps++;
    }
  }
  wcsdst->nps = nps;

  // Alternate linear transformations.
  if (wcssrc->cd) {
    srcp = wcssrc->cd;
    dstp = wcsdst->cd;
    for (int i = 0; i < *nsub; i++) {
      for (int j = 0; j < *nsub; j++, dstp++) {
        if (axes[i] > 0 && axes[j] > 0) {
          int k = (axes[i]-1)*naxis + (axes[j]-1);
          *dstp = *(srcp+k);
        } else if (i == j && wcssrc->altlin & 2) {
          // A new axis is being created where CDi_ja was present in the input
          // header, so override the default value of 0 set by wcsinit().
          *dstp = 1.0;
        }
      }
    }
  }

  if (wcssrc->crota) {
    srcp = wcssrc->crota;
    dstp = wcsdst->crota;
    for (int i = 0; i < *nsub; i++, dstp++) {
      if (axes[i] > 0) {
        int k = axes[i] - 1;
        *dstp = *(srcp+k);
      }
    }
  }

  wcsdst->altlin = wcssrc->altlin;
  wcsdst->velref = wcssrc->velref;

  // Auxiliary coordinate system information.
  strncpy(wcsdst->alt, wcssrc->alt, 4);
  wcsdst->colnum = wcssrc->colnum;

  for (int i = 0; i < *nsub; i++) {
    if (axes[i] > 0) {
      int k = axes[i] - 1;
      if (wcssrc->colax) wcsdst->colax[i] = wcssrc->colax[k];
      if (wcssrc->cname) strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
      if (wcssrc->crder) wcsdst->crder[i] = wcssrc->crder[k];
      if (wcssrc->csyer) wcsdst->csyer[i] = wcssrc->csyer[k];
      if (wcssrc->czphs) wcsdst->czphs[i] = wcssrc->czphs[k];
      if (wcssrc->cperi) wcsdst->cperi[i] = wcssrc->cperi[k];
    }
  }

  strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);

  strncpy(wcsdst->timesys, wcssrc->timesys, 72);
  strncpy(wcsdst->trefpos, wcssrc->trefpos, 72);
  strncpy(wcsdst->trefdir, wcssrc->trefdir, 72);
  strncpy(wcsdst->plephem, wcssrc->plephem, 72);

  strncpy(wcsdst->timeunit, wcssrc->timeunit, 72);
  strncpy(wcsdst->dateref,  wcssrc->dateref, 72);
  wcsdst->mjdref[0] = wcssrc->mjdref[0];
  wcsdst->mjdref[1] = wcssrc->mjdref[1];
  wcsdst->timeoffs  = wcssrc->timeoffs;

  strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);
  strncpy(wcsdst->datebeg, wcssrc->datebeg, 72);
  strncpy(wcsdst->dateavg, wcssrc->dateavg, 72);
  strncpy(wcsdst->dateend, wcssrc->dateend, 72);

  wcsdst->mjdobs  = wcssrc->mjdobs;
  wcsdst->mjdbeg  = wcssrc->mjdbeg;
  wcsdst->mjdavg  = wcssrc->mjdavg;
  wcsdst->mjdend  = wcssrc->mjdend;
  wcsdst->jepoch  = wcssrc->jepoch;
  wcsdst->bepoch  = wcssrc->bepoch;
  wcsdst->tstart  = wcssrc->tstart;
  wcsdst->tstop   = wcssrc->tstop;
  wcsdst->xposure = wcssrc->xposure;
  wcsdst->telapse = wcssrc->telapse;

  wcsdst->timsyer  = wcssrc->timsyer;
  wcsdst->timrder  = wcssrc->timrder;
  wcsdst->timedel  = wcssrc->timedel;
  wcsdst->timepixr = wcssrc->timepixr;

  wcsdst->obsgeo[0] = wcssrc->obsgeo[0];
  wcsdst->obsgeo[1] = wcssrc->obsgeo[1];
  wcsdst->obsgeo[2] = wcssrc->obsgeo[2];
  wcsdst->obsgeo[3] = wcssrc->obsgeo[3];
  wcsdst->obsgeo[4] = wcssrc->obsgeo[4];
  wcsdst->obsgeo[5] = wcssrc->obsgeo[5];

  strncpy(wcsdst->obsorbit, wcssrc->obsorbit, 72);
  strncpy(wcsdst->radesys,  wcssrc->radesys, 72);
  wcsdst->equinox = wcssrc->equinox;
  strncpy(wcsdst->specsys,  wcssrc->specsys, 72);
  strncpy(wcsdst->ssysobs,  wcssrc->ssysobs, 72);
  wcsdst->velosys = wcssrc->velosys;
  wcsdst->zsource = wcssrc->zsource;
  strncpy(wcsdst->ssyssrc,  wcssrc->ssyssrc, 72);
  wcsdst->velangl = wcssrc->velangl;


  // Additional auxiliary coordinate system information.
  if (wcssrc->aux && !wcsdst->aux) {
    if ((wcsdst->aux = calloc(1, sizeof(struct auxprm))) == 0x0) {
      status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      goto cleanup;
    }

    wcsdst->m_aux = wcsdst->aux;

    wcsdst->aux->rsun_ref = wcssrc->aux->rsun_ref;
    wcsdst->aux->dsun_obs = wcssrc->aux->dsun_obs;
    wcsdst->aux->crln_obs = wcssrc->aux->crln_obs;
    wcsdst->aux->hgln_obs = wcssrc->aux->hgln_obs;
    wcsdst->aux->hglt_obs = wcssrc->aux->hglt_obs;

    wcsdst->aux->a_radius = wcssrc->aux->a_radius;
    wcsdst->aux->b_radius = wcssrc->aux->b_radius;
    wcsdst->aux->c_radius = wcssrc->aux->c_radius;
    wcsdst->aux->blon_obs = wcssrc->aux->blon_obs;
    wcsdst->aux->blat_obs = wcssrc->aux->blat_obs;
    wcsdst->aux->bdis_obs = wcssrc->aux->bdis_obs;
  }


  // Coordinate lookup tables; only copy what's needed.
  wcsdst->ntab = 0;
  for (int itab = 0; itab < wcssrc->ntab; itab++) {
    // Is this table wanted?
    for (int m = 0; m < wcssrc->tab[itab].M; m++) {
      int i = wcssrc->tab[itab].map[m];

      if (map[i]) {
        wcsdst->ntab++;
        break;
      }
    }
  }

  if (wcsdst->ntab) {
    // Allocate memory for tabprm structs.
    if ((wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm))) == 0x0) {
      wcsdst->ntab = 0;

      status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      goto cleanup;
    }

    wcsdst->m_tab = wcsdst->tab;
  }

  struct tabprm *tab = wcsdst->tab;
  for (int itab = 0; itab < wcssrc->ntab; itab++) {
    for (int m = 0; m < wcssrc->tab[itab].M; m++) {
      int i = wcssrc->tab[itab].map[m];

      if (map[i]) {
        tab->flag = -1;
        if ((status = tabcpy(1, wcssrc->tab + itab, tab))) {
          wcserr_set(WCS_ERRMSG(wcs_taberr[status]));
          goto cleanup;
        }

        // Translate axis numbers in tab->map[].
        for (int m = 0; m < wcssrc->tab[itab].M; m++) {
          // Table axis mapping, followed by...
          int i = wcssrc->tab[itab].map[m];

          // ...subimaging axis mapping.
          int j = map[i] - 1;
          if (j < 0) {
            // In general, multi-dimensional tables (i.e. with M > 1) are not
            // separable, so if one axis is selected then all must be.
            status = wcserr_set(WCSERR_SET(WCSERR_NON_SEPARABLE),
              "Table with M>1 depends on axis excluded from the subimage");
            goto cleanup;
          }

          tab->map[m] = j;
        }

        tab++;
        break;
      }
    }
  }


  // Distortion parameters (in linprm).
  for (int m = 0; m < 2; m++) {
    struct disprm *dissrc, *disdst;
    if (m == 0) {
      dissrc = wcssrc->lin.dispre;
      disdst = wcsdst->lin.dispre;
    } else {
      dissrc = wcssrc->lin.disseq;
      disdst = wcsdst->lin.disseq;
    }

    if (dissrc) {
      disdst->naxis = *nsub;

      // Distortion type and maximum distortion (but not total distortion).
      for (int j = 0; j < *nsub; j++) {
        if (axes[j] > 0) {
          int k = axes[j] - 1;
          strncpy(disdst->dtype[j], dissrc->dtype[k], 72);
          disdst->maxdis[j] = dissrc->maxdis[k];
        }
      }

      // DPja or DQia keyvalues.
      int ndp = 0;
      struct dpkey *dpdst = disdst->dp;
      for (int j = 0; j < *nsub; j++) {
        if (axes[j] == 0) continue;

        // Determine the axis mapping.
        int axmap[NAXMAX];
        for (int jhat = 0; jhat < NAXMAX; jhat++) {
          axmap[jhat] = -1;
        }

        int Nhat = 0;
        struct dpkey *dpsrc = dissrc->dp;
        for (int idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
          if (dpsrc->j != axes[j]) continue;
          if (dpsrc->field[1] != pq[m]) continue;
          char *fp;
          if ((fp = strchr(dpsrc->field, '.')) == 0x0) continue;
          fp++;

          if (strcmp(fp, "NAXES") == 0) {
            Nhat = dpkeyi(dpsrc);
          } else if (strncmp(fp, "AXIS.", 5) == 0) {
            int jhat;
            sscanf(fp+5, "%d", &jhat);
            axmap[jhat-1] = dpkeyi(dpsrc) - 1;
          }
        }

        for (int jhat = 0; jhat < Nhat; jhat++) {
          if (axmap[jhat] < 0) {
            axmap[jhat] = jhat;
          }
        }

        // Copy the DPja or DQia keyvalues.
        dpsrc = dissrc->dp;
        for (int idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
          if (dpsrc->j != axes[j]) continue;
          if (dpsrc->field[1] != pq[m]) continue;
          char *fp;
          if ((fp = strchr(dpsrc->field, '.')) == 0x0) continue;
          fp++;

          if (strncmp(fp, "AXIS.", 5) == 0) {
            // Skip it, we will create our own later.
            continue;
          }

          *dpdst = *dpsrc;
          char ctmp[16];
          snprintf(ctmp, 16, "%d", j+1);
          dpdst->field[2] = ctmp[0];
          dpdst->j = j+1;

          ndp++;
          dpdst++;

          if (strcmp(fp, "NAXES") == 0) {
            for (int jhat = 0; jhat < Nhat; jhat++) {
              strncpy(dpdst->field, dpsrc->field, 72);
              dpdst->field[2] = ctmp[0];
              fp = strchr(dpdst->field, '.') + 1;
              size_t fsize = (dpdst->field + 72) - fp;
              snprintf(fp, fsize, "AXIS.%d", jhat+1);
              dpdst->j = j+1;
              dpdst->type = 0;
              dpdst->value.i = map[axmap[jhat]];

              ndp++;
              dpdst++;
            }
          }
        }
      }

      disdst->ndp = ndp;
    }
  }


cleanup:
  if (itmp) free(itmp);
  if (dealloc) {
    free(axes);
  }

  if (status && wcsdst->m_aux) {
    free(wcsdst->m_aux);
    wcsdst->aux   = 0x0;
    wcsdst->m_aux = 0x0;
  }

  if (status && wcsdst->m_tab) {
    tabfree(wcsdst->m_tab);
  }

  return status;
}

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

int wcscompare(
  int cmp,
  double tol,
  const struct wcsprm *wcs1,
  const struct wcsprm *wcs2,
  int *equal)

{
  int status;

  if (wcs1  == 0x0) return WCSERR_NULL_POINTER;
  if (wcs2  == 0x0) return WCSERR_NULL_POINTER;
  if (equal == 0x0) return WCSERR_NULL_POINTER;

  *equal = 0;

  if (wcs1->naxis != wcs2->naxis) {
    return 0;
  }

  int naxis = wcs1->naxis;
  int naxis2 = wcs1->naxis*wcs1->naxis;

  if (cmp & WCSCOMPARE_CRPIX) {
    // Don't compare crpix.
  } else if (cmp & WCSCOMPARE_TILING) {
    for (int i = 0; i < naxis; ++i) {
      double diff = wcs1->crpix[i] - wcs2->crpix[i];
      if ((double)(int)(diff) != diff) {
        return 0;
      }
    }
  } else {
    if (!wcsutil_dblEq(naxis, tol, wcs1->crpix, wcs2->crpix)) {
      return 0;
    }
  }

  if (!wcsutil_dblEq(naxis2, tol, wcs1->pc, wcs2->pc) ||
      !wcsutil_dblEq(naxis, tol, wcs1->cdelt, wcs2->cdelt) ||
      !wcsutil_dblEq(naxis, tol, wcs1->crval, wcs2->crval) ||
      !wcsutil_strEq(naxis, wcs1->cunit, wcs2->cunit) ||
      !wcsutil_strEq(naxis, wcs1->ctype, wcs2->ctype) ||
      !wcsutil_dblEq(1, tol, &wcs1->lonpole, &wcs2->lonpole) ||
      !wcsutil_dblEq(1, tol, &wcs1->latpole, &wcs2->latpole) ||
      !wcsutil_dblEq(1, tol, &wcs1->restfrq, &wcs2->restfrq) ||
      !wcsutil_dblEq(1, tol, &wcs1->restwav, &wcs2->restwav) ||
      wcs1->npv != wcs2->npv ||
      wcs1->nps != wcs2->nps) {
    return 0;
  }

  // Compare pv cards, which may not be in the same order
  for (int i = 0; i < wcs1->npv; ++i) {
    int j;
    for (j = 0; j < wcs2->npv; ++j) {
      if (wcs1->pv[i].i == wcs2->pv[j].i &&
          wcs1->pv[i].m == wcs2->pv[j].m) {
        if (!wcsutil_dblEq(1, tol, &wcs1->pv[i].value, &wcs2->pv[j].value)) {
          return 0;
        }
        break;
      }
    }
    // We didn't find a match, so they are not equal
    if (j == wcs2->npv) {
      return 0;
    }
  }

  // Compare ps cards, which may not be in the same order
  for (int i = 0; i < wcs1->nps; ++i) {
    int j;
    for (j = 0; j < wcs2->nps; ++j) {
      if (wcs1->ps[i].i == wcs2->ps[j].i &&
          wcs1->ps[i].m == wcs2->ps[j].m) {
        if (strncmp(wcs1->ps[i].value, wcs2->ps[j].value, 72) != 0) {
          return 0;
        }
        break;
      }
    }
    // We didn't find a match, so they are not equal
    if (j == wcs2->nps) {
      return 0;
    }
  }

  if (abs(wcs1->flag) != WCSSET || abs(wcs2->flag) != WCSSET) {
    if (!wcsutil_dblEq(naxis2, tol, wcs1->cd, wcs2->cd) ||
        !wcsutil_dblEq(naxis, tol, wcs1->crota, wcs2->crota) ||
        wcs1->altlin != wcs2->altlin ||
        wcs1->velref != wcs2->velref) {
      return 0;
    }
  }

  if (!(cmp & WCSCOMPARE_ANCILLARY)) {
    if (strncmp(wcs1->alt, wcs2->alt, 4) != 0 ||
        wcs1->colnum != wcs2->colnum ||
        !wcsutil_intEq(naxis, wcs1->colax, wcs2->colax) ||
        !wcsutil_strEq(naxis, wcs1->cname, wcs2->cname) ||
        !wcsutil_dblEq(naxis, tol, wcs1->crder, wcs2->crder) ||
        !wcsutil_dblEq(naxis, tol, wcs1->csyer, wcs2->csyer) ||
        !wcsutil_dblEq(naxis, tol, wcs1->czphs, wcs2->czphs) ||
        !wcsutil_dblEq(naxis, tol, wcs1->cperi, wcs2->cperi) ||
        strncmp(wcs1->wcsname,  wcs2->wcsname,  72) != 0 ||
        strncmp(wcs1->timesys,  wcs2->timesys,  72) != 0 ||
        strncmp(wcs1->trefpos,  wcs2->trefpos,  72) != 0 ||
        strncmp(wcs1->trefdir,  wcs2->trefdir,  72) != 0 ||
        strncmp(wcs1->plephem,  wcs2->plephem,  72) != 0 ||
        strncmp(wcs1->timeunit, wcs2->timeunit, 72) != 0 ||
        strncmp(wcs1->dateref,  wcs2->dateref,  72) != 0 ||
        !wcsutil_dblEq(2, tol,  wcs1->mjdref,    wcs2->mjdref)   ||
        !wcsutil_dblEq(1, tol, &wcs1->timeoffs, &wcs2->timeoffs) ||
        strncmp(wcs1->dateobs,  wcs2->dateobs, 72) != 0 ||
        strncmp(wcs1->datebeg,  wcs2->datebeg, 72) != 0 ||
        strncmp(wcs1->dateavg,  wcs2->dateavg, 72) != 0 ||
        strncmp(wcs1->dateend,  wcs2->dateend, 72) != 0 ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdobs,   &wcs2->mjdobs)   ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdbeg,   &wcs2->mjdbeg)   ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdavg,   &wcs2->mjdavg)   ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdend,   &wcs2->mjdend)   ||
        !wcsutil_dblEq(1, tol, &wcs1->jepoch,   &wcs2->jepoch)   ||
        !wcsutil_dblEq(1, tol, &wcs1->bepoch,   &wcs2->bepoch)   ||
        !wcsutil_dblEq(1, tol, &wcs1->tstart,   &wcs2->tstart)   ||
        !wcsutil_dblEq(1, tol, &wcs1->tstop,    &wcs2->tstop)    ||
        !wcsutil_dblEq(1, tol, &wcs1->xposure,  &wcs2->xposure)  ||
        !wcsutil_dblEq(1, tol, &wcs1->telapse,  &wcs2->telapse)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timsyer,  &wcs2->timsyer)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timrder,  &wcs2->timrder)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timedel,  &wcs2->timedel)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timepixr, &wcs2->timepixr) ||
        !wcsutil_dblEq(6, tol,  wcs1->obsgeo,    wcs2->obsgeo)   ||
        strncmp(wcs1->obsorbit, wcs2->obsorbit, 72) != 0 ||
        strncmp(wcs1->radesys,  wcs2->radesys,  72) != 0 ||
        !wcsutil_dblEq(1, tol, &wcs1->equinox,  &wcs2->equinox)  ||
        strncmp(wcs1->specsys,  wcs2->specsys,  72) != 0 ||
        strncmp(wcs1->ssysobs,  wcs2->ssysobs,  72) != 0 ||
        !wcsutil_dblEq(1, tol, &wcs1->velosys,  &wcs2->velosys)  ||
        !wcsutil_dblEq(1, tol, &wcs1->zsource,  &wcs2->zsource)  ||
        strncmp(wcs1->ssyssrc,  wcs2->ssyssrc,  72) != 0 ||
        !wcsutil_dblEq(1, tol, &wcs1->velangl,  &wcs2->velangl)) {
      return 0;
    }

    // Compare additional auxiliary parameters.
    if (wcs1->aux && wcs2->aux) {
      if (!wcsutil_dblEq(1, tol, &wcs1->aux->rsun_ref, &wcs2->aux->rsun_ref) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->dsun_obs, &wcs2->aux->dsun_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->crln_obs, &wcs2->aux->crln_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->hgln_obs, &wcs2->aux->hgln_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->hglt_obs, &wcs2->aux->hglt_obs)) {
        return 0;
      }

      if (!wcsutil_dblEq(1, tol, &wcs1->aux->a_radius, &wcs2->aux->a_radius) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->b_radius, &wcs2->aux->b_radius) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->c_radius, &wcs2->aux->c_radius) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->blon_obs, &wcs2->aux->blon_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->blat_obs, &wcs2->aux->blat_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->bdis_obs, &wcs2->aux->bdis_obs)) {
        return 0;
      }
    } else if (wcs1->aux || wcs2->aux) {
      return 0;
    }
  }

  // Compare tabular parameters
  if (wcs1->ntab != wcs2->ntab) {
    return 0;
  }

  for (int i = 0; i < wcs1->ntab; ++i) {
    int tab_equal;
    if ((status = tabcmp(0, tol, &wcs1->tab[i], &wcs2->tab[i], &tab_equal))) {
      return status;
    }
    if (!tab_equal) {
      return 0;
    }
  }

  *equal = 1;
  return 0;
}

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

int wcsfree(struct wcsprm *wcs)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (wcs->flag == -1) {
    wcs->lin.flag = -1;

  } else {
    // Optionally allocated by wcsinit() for given parameters.
    if (wcs->m_flag == WCSSET) {
      // Start by cleaning the slate.
      if (wcs->crpix == wcs->m_crpix) wcs->crpix = 0x0;
      if (wcs->pc    == wcs->m_pc)    wcs->pc    = 0x0;
      if (wcs->cdelt == wcs->m_cdelt) wcs->cdelt = 0x0;
      if (wcs->crval == wcs->m_crval) wcs->crval = 0x0;
      if (wcs->cunit == wcs->m_cunit) wcs->cunit = 0x0;
      if (wcs->ctype == wcs->m_ctype) wcs->ctype = 0x0;
      if (wcs->pv    == wcs->m_pv)    wcs->pv    = 0x0;
      if (wcs->ps    == wcs->m_ps)    wcs->ps    = 0x0;
      if (wcs->cd    == wcs->m_cd)    wcs->cd    = 0x0;
      if (wcs->crota == wcs->m_crota) wcs->crota = 0x0;
      if (wcs->colax == wcs->m_colax) wcs->colax = 0x0;
      if (wcs->cname == wcs->m_cname) wcs->cname = 0x0;
      if (wcs->crder == wcs->m_crder) wcs->crder = 0x0;
      if (wcs->csyer == wcs->m_csyer) wcs->csyer = 0x0;
      if (wcs->czphs == wcs->m_czphs) wcs->czphs = 0x0;
      if (wcs->cperi == wcs->m_cperi) wcs->cperi = 0x0;

      if (wcs->aux   == wcs->m_aux)   wcs->aux   = 0x0;
      if (wcs->tab   == wcs->m_tab)   wcs->tab   = 0x0;
      if (wcs->wtb   == wcs->m_wtb)   wcs->wtb   = 0x0;

      // Now release the memory.
      if (wcs->m_crpix)  free(wcs->m_crpix);
      if (wcs->m_pc)     free(wcs->m_pc);
      if (wcs->m_cdelt)  free(wcs->m_cdelt);
      if (wcs->m_crval)  free(wcs->m_crval);
      if (wcs->m_cunit)  free(wcs->m_cunit);
      if (wcs->m_ctype)  free(wcs->m_ctype);
      if (wcs->m_pv)     free(wcs->m_pv);
      if (wcs->m_ps)     free(wcs->m_ps);
      if (wcs->m_cd)     free(wcs->m_cd);
      if (wcs->m_crota)  free(wcs->m_crota);
      if (wcs->m_colax)  free(wcs->m_colax);
      if (wcs->m_cname)  free(wcs->m_cname);
      if (wcs->m_crder)  free(wcs->m_crder);
      if (wcs->m_csyer)  free(wcs->m_csyer);
      if (wcs->m_czphs)  free(wcs->m_czphs);
      if (wcs->m_cperi)  free(wcs->m_cperi);

      // May have been allocated by wcspih() or wcssub().
      if (wcs->m_aux) free(wcs->m_aux);

      // Allocated unconditionally by wcstab().
      if (wcs->m_tab) {
        for (int itab = 0; itab < wcs->ntab; itab++) {
          tabfree(wcs->m_tab + itab);
        }

        free(wcs->m_tab);
      }
      if (wcs->m_wtb) free(wcs->m_wtb);
    }

    // Allocated unconditionally by wcsset().
    if (wcs->types) free(wcs->types);

    if (wcs->lin.crpix == wcs->m_crpix) wcs->lin.crpix = 0x0;
    if (wcs->lin.pc    == wcs->m_pc)    wcs->lin.pc    = 0x0;
    if (wcs->lin.cdelt == wcs->m_cdelt) wcs->lin.cdelt = 0x0;
  }

  wcs->m_flag   = 0;
  wcs->m_naxis  = 0x0;
  wcs->m_crpix  = 0x0;
  wcs->m_pc     = 0x0;
  wcs->m_cdelt  = 0x0;
  wcs->m_crval  = 0x0;
  wcs->m_cunit  = 0x0;
  wcs->m_ctype  = 0x0;
  wcs->m_pv     = 0x0;
  wcs->m_ps     = 0x0;
  wcs->m_cd     = 0x0;
  wcs->m_crota  = 0x0;
  wcs->m_colax  = 0x0;
  wcs->m_cname  = 0x0;
  wcs->m_crder  = 0x0;
  wcs->m_csyer  = 0x0;
  wcs->m_czphs  = 0x0;
  wcs->m_cperi  = 0x0;

  wcs->m_aux    = 0x0;

  wcs->ntab  = 0;
  wcs->m_tab = 0x0;
  wcs->nwtb  = 0;
  wcs->m_wtb = 0x0;

  wcs->types = 0x0;

  linfree(&(wcs->lin));
  celfree(&(wcs->cel));
  spcfree(&(wcs->spc));

  wcserr_clear(&(wcs->err));

  wcs->flag = 0;

  return 0;
}

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

int wcstrim(struct wcsprm *wcs)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (wcs->m_flag != WCSSET) {
    // Nothing to do.
    return 0;
  }

  if (abs(wcs->flag) != WCSSET) {
    return WCSERR_UNSET;
  }

  if (wcs->npv < wcs->npvmax) {
    if (wcs->m_pv) {
      if (wcs->npv == 0) {
        free(wcs->m_pv);
        wcs->pv = wcs->m_pv = 0x0;
      } else {
        size_t size = wcs->npv * sizeof(struct pvcard);
        // No error if realloc() fails, it will leave the array untouched.
        struct pvcard *pvp = realloc(wcs->m_pv, size);
        if (pvp != 0x0) {
          wcs->pv = wcs->m_pv = pvp;
          wcs->npvmax = wcs->npv;
        }
      }
    }
  }

  if (wcs->nps < wcs->npsmax) {
    if (wcs->m_ps) {
      if (wcs->nps == 0) {
        free(wcs->m_ps);
        wcs->ps = wcs->m_ps = 0x0;
      } else {
        size_t size = wcs->nps * sizeof(struct pscard);
        // No error if realloc() fails, it will leave the array untouched.
        struct pscard *psp = realloc(wcs->m_ps, size);
        if (psp != 0x0) {
          wcs->ps = wcs->m_ps = psp;
          wcs->npsmax = wcs->nps;
        }
      }
    }
  }

  if (!(wcs->altlin & 2)) {
    if (wcs->m_cd) {
      free(wcs->m_cd);
      wcs->cd = wcs->m_cd = 0x0;
    }
  }

  if (!(wcs->altlin & 4)) {
    if (wcs->m_crota) {
      free(wcs->m_crota);
      wcs->crota = wcs->m_crota = 0x0;
    }
  }

  if (wcs->colax) {
    if (wcsutil_all_ival(wcs->naxis, 0, wcs->colax)) {
      free(wcs->m_colax);
      wcs->colax = wcs->m_colax = 0x0;
    }
  }

  if (wcs->cname) {
    if (wcsutil_all_sval(wcs->naxis, "", (const char (*)[72])wcs->cname)) {
      free(wcs->m_cname);
      wcs->cname = wcs->m_cname = 0x0;
    }
  }

  if (wcs->crder) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->crder)) {
      free(wcs->m_crder);
      wcs->crder = wcs->m_crder = 0x0;
    }
  }

  if (wcs->csyer) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->csyer)) {
      free(wcs->m_csyer);
      wcs->csyer = wcs->m_csyer = 0x0;
    }
  }

  if (wcs->czphs) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->czphs)) {
      free(wcs->m_czphs);
      wcs->czphs = wcs->m_czphs = 0x0;
    }
  }

  if (wcs->cperi) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->cperi)) {
      free(wcs->m_cperi);
      wcs->cperi = wcs->m_cperi = 0x0;
    }
  }

  // Reset the struct (to store the new checksum).
  int status;
  wcs->flag = (wcs->flag == -WCSSET) ? 1 : 0;
  if ((status = wcsset(wcs))) return status;

  return 0;
}

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

int wcssize(const struct wcsprm *wcs, int sizes[2])

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

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

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

  int exsizes[2];
  int naxis = wcs->naxis;

  // wcsprm::crpix[].
  sizes[1] += naxis * (int)sizeof(double);

  // wcsprm::pc[].
  sizes[1] += naxis*naxis * (int)sizeof(double);

  // wcsprm::cdelt[].
  sizes[1] += naxis * (int)sizeof(double);

  // wcsprm::crval[].
  sizes[1] += naxis * (int)sizeof(double);

  // wcsprm::cunit[].
  if (wcs->cunit) {
    sizes[1] += naxis * (int)sizeof(char [72]);
  }

  // wcsprm::ctype[].
  sizes[1] += naxis * (int)sizeof(char [72]);

  // wcsprm::pv[].
  if (wcs->pv) {
    sizes[1] += wcs->npvmax * (int)sizeof(struct pvcard);
  }

  // wcsprm::ps[].
  if (wcs->ps) {
    sizes[1] += wcs->npsmax * (int)sizeof(struct pscard);
  }

  // wcsprm::cd[].
  if (wcs->cd) {
    sizes[1] += naxis*naxis * (int)sizeof(double);
  }

  // wcsprm::crota[].
  if (wcs->crota) {
    sizes[1] += naxis * (int)sizeof(double);
  }

  // wcsprm::colax[].
  if (wcs->colax) {
    sizes[1] += naxis * (int)sizeof(int);
  }

  // wcsprm::cname[].
  if (wcs->cname) {
    sizes[1] += naxis * (int)sizeof(char [72]);
  }

  // wcsprm::crder[].
  if (wcs->crder) {
    sizes[1] += naxis * (int)sizeof(double);
  }

  // wcsprm::csyer[].
  if (wcs->csyer) {
    sizes[1] += naxis * (int)sizeof(double);
  }

  // wcsprm::czphs[].
  if (wcs->czphs) {
    sizes[1] += naxis * (int)sizeof(double);
  }

  // wcsprm::cperi[].
  if (wcs->cperi) {
    sizes[1] += naxis * (int)sizeof(double);
  }

  // wcsprm::aux.
  if (wcs->aux) {
    sizes[1] += (int)sizeof(struct auxprm);
  }

  // wcsprm::tab.
  for (int itab = 0; itab < wcs->ntab; itab++) {
    tabsize(wcs->tab + itab, exsizes);
    sizes[1] += exsizes[0] + exsizes[1];
  }

  // wcsprm::wtb.
  if (wcs->wtb) {
    sizes[1] += wcs->nwtb * (int)sizeof(struct wtbarr);
  }

  // wcsprm::lin.
  linsize(&(wcs->lin), exsizes);
  sizes[1] += exsizes[1];

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

  return 0;
}

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

int auxsize(const struct auxprm *aux, int sizes[2])

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

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

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

  return 0;
}

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

int wcsenq(const struct wcsprm *wcs, int enquiry)

{
  // Initialize.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  int answer = 0;

  if (enquiry & WCSENQ_MEM) {
    if (wcs->m_flag != WCSSET) return 0;
    answer = 1;
  }

  if (enquiry & WCSENQ_SET) {
    if (abs(wcs->flag) != WCSSET) return 0;
    answer = 1;
  }

  if (enquiry & WCSENQ_BYP) {
    if (wcs->flag != 1 && wcs->flag != -WCSSET) return 0;
    answer = 1;
  }

  if (enquiry & WCSENQ_CHK) {
    if (abs(wcs->flag) != WCSSET) return 0;
    if (wcs->chksum != wcs_chksum(wcs)) return 0;
    answer = 1;
  }

  return answer;
}

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

static void wcsprt_auxc(const char *name, const char *value)
{
  if (value[0] == '\0') {
    wcsprintf("   %s: UNDEFINED\n", name);
  } else {
    wcsprintf("   %s: \"%s\"\n", name, value);
  }
}

static void wcsprt_auxd(const char *name, double value)
{
  if (undefined(value)) {
    wcsprintf("   %s: UNDEFINED\n", name);
  } else {
    wcsprintf("   %s:  %15.9f\n", name, value);
  }
}

int wcsprt(const struct wcsprm *wcs)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (abs(wcs->flag) != WCSSET) {
    wcsprintf("The wcsprm struct is UNINITIALIZED.\n");
    return 0;
  }

  // Parameters supplied...
  wcsprintf("       flag: %d\n", wcs->flag);
  wcsprintf("      naxis: %d\n", wcs->naxis);
  WCSPRINTF_PTR("      crpix: ", wcs->crpix, "\n");
  wcsprintf("            ");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("  %#- 11.5g", wcs->crpix[i]);
  }
  wcsprintf("\n");

  // ...linear transformation.
  int k = 0;
  WCSPRINTF_PTR("         pc: ", wcs->pc, "\n");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("    pc[%d][]:", i);
    for (int j = 0; j < wcs->naxis; j++) {
      wcsprintf("  %#- 11.5g", wcs->pc[k++]);
    }
    wcsprintf("\n");
  }

  // ...coordinate increment at reference point.
  WCSPRINTF_PTR("      cdelt: ", wcs->cdelt, "\n");
  wcsprintf("            ");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("  %#- 11.5g", wcs->cdelt[i]);
  }
  wcsprintf("\n");

  // ...coordinate value at reference point.
  WCSPRINTF_PTR("      crval: ", wcs->crval, "\n");
  wcsprintf("            ");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("  %#- 11.5g", wcs->crval[i]);
  }
  wcsprintf("\n");

  // ...coordinate units and type.
  WCSPRINTF_PTR("      cunit: ", wcs->cunit, "\n");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("             \"%s\"\n", wcs->cunit[i]);
  }

  WCSPRINTF_PTR("      ctype: ", wcs->ctype, "\n");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("             \"%s\"\n", wcs->ctype[i]);
  }

  // ...celestial and spectral transformation parameters.
  if (undefined(wcs->lonpole)) {
    wcsprintf("    lonpole: UNDEFINED\n");
  } else {
    wcsprintf("    lonpole: %9f\n", wcs->lonpole);
  }
  wcsprintf("    latpole: %9f\n", wcs->latpole);
  wcsprintf("    restfrq: %f\n", wcs->restfrq);
  wcsprintf("    restwav: %f\n", wcs->restwav);

  // ...parameter values.
  wcsprintf("        npv: %d\n", wcs->npv);
  wcsprintf("     npvmax: %d\n", wcs->npvmax);
  WCSPRINTF_PTR("         pv: ", wcs->pv, "\n");
  for (int k = 0; k < wcs->npv; k++) {
    wcsprintf("             %3d%4d  %#- 11.5g\n", (wcs->pv[k]).i,
      (wcs->pv[k]).m, (wcs->pv[k]).value);
  }
  wcsprintf("        nps: %d\n", wcs->nps);
  wcsprintf("     npsmax: %d\n", wcs->npsmax);
  WCSPRINTF_PTR("         ps: ", wcs->ps, "\n");
  for (int k = 0; k < wcs->nps; k++) {
    wcsprintf("             %3d%4d  %s\n", (wcs->ps[k]).i,
      (wcs->ps[k]).m, (wcs->ps[k]).value);
  }

  // ...alternate linear transformations.
  k = 0;
  WCSPRINTF_PTR("         cd: ", wcs->cd, "\n");
  if (wcs->cd) {
    for (int i = 0; i < wcs->naxis; i++) {
      wcsprintf("    cd[%d][]:", i);
      for (int j = 0; j < wcs->naxis; j++) {
        wcsprintf("  %#- 11.5g", wcs->cd[k++]);
      }
      wcsprintf("\n");
    }
  }

  WCSPRINTF_PTR("      crota: ", wcs->crota, "\n");
  if (wcs->crota) {
    wcsprintf("            ");
    for (int i = 0; i < wcs->naxis; i++) {
      wcsprintf("  %#- 11.5g", wcs->crota[i]);
    }
    wcsprintf("\n");
  }

  wcsprintf("     altlin: %d\n", wcs->altlin);
  wcsprintf("     velref: %d\n", wcs->velref);



  // ...auxiliary coordinate system information.
  wcsprintf("        alt: '%c'\n", wcs->alt[0]);
  wcsprintf("     colnum: %d\n", wcs->colnum);

  WCSPRINTF_PTR("      colax: ", wcs->colax, "\n");
  if (wcs->colax) {
    wcsprintf("           ");
    for (int i = 0; i < wcs->naxis; i++) {
      wcsprintf("  %5d", wcs->colax[i]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      cname: ", wcs->cname, "\n");
  if (wcs->cname) {
    for (int i = 0; i < wcs->naxis; i++) {
      if (wcs->cname[i][0] == '\0') {
        wcsprintf("             UNDEFINED\n");
      } else {
        wcsprintf("             \"%s\"\n", wcs->cname[i]);
      }
    }
  }

  WCSPRINTF_PTR("      crder: ", wcs->crder, "\n");
  if (wcs->crder) {
    wcsprintf("           ");
    for (int i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->crder[i])) {
        wcsprintf("    UNDEFINED");
      } else {
        wcsprintf("  %#- 11.5g", wcs->crder[i]);
      }
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      csyer: ", wcs->csyer, "\n");
  if (wcs->csyer) {
    wcsprintf("           ");
    for (int i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->csyer[i])) {
        wcsprintf("    UNDEFINED");
      } else {
        wcsprintf("  %#- 11.5g", wcs->csyer[i]);
      }
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      czphs: ", wcs->czphs, "\n");
  if (wcs->czphs) {
    wcsprintf("           ");
    for (int i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->czphs[i])) {
        wcsprintf("    UNDEFINED");
      } else {
        wcsprintf("  %#- 11.5g", wcs->czphs[i]);
      }
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      cperi: ", wcs->cperi, "\n");
  if (wcs->cperi) {
    wcsprintf("           ");
    for (int i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->cperi[i])) {
        wcsprintf("    UNDEFINED");
      } else {
        wcsprintf("  %#- 11.5g", wcs->cperi[i]);
      }
    }
    wcsprintf("\n");
  }

  wcsprt_auxc(" wcsname", wcs->wcsname);

  wcsprt_auxc(" timesys", wcs->timesys);
  wcsprt_auxc(" trefpos", wcs->trefpos);
  wcsprt_auxc(" trefdir", wcs->trefdir);
  wcsprt_auxc(" plephem", wcs->plephem);
  wcsprt_auxc("timeunit", wcs->timeunit);
  wcsprt_auxc(" dateref", wcs->dateref);
  wcsprintf("     mjdref: ");
  for (int k = 0; k < 2; k++) {
    if (undefined(wcs->mjdref[k])) {
      wcsprintf("       UNDEFINED");
    } else {
      wcsprintf(" %15.9f", wcs->mjdref[k]);
    }
  }
  wcsprintf("\n");
  wcsprt_auxd("timeoffs", wcs->timeoffs);

  wcsprt_auxc(" dateobs", wcs->dateobs);
  wcsprt_auxc(" datebeg", wcs->datebeg);
  wcsprt_auxc(" dateavg", wcs->dateavg);
  wcsprt_auxc(" dateend", wcs->dateend);
  wcsprt_auxd("  mjdobs", wcs->mjdobs);
  wcsprt_auxd("  mjdbeg", wcs->mjdbeg);
  wcsprt_auxd("  mjdavg", wcs->mjdavg);
  wcsprt_auxd("  mjdend", wcs->mjdend);
  wcsprt_auxd("  jepoch", wcs->jepoch);
  wcsprt_auxd("  bepoch", wcs->bepoch);
  wcsprt_auxd("  tstart", wcs->tstart);
  wcsprt_auxd("   tstop", wcs->tstop);
  wcsprt_auxd(" xposure", wcs->xposure);
  wcsprt_auxd(" telapse", wcs->telapse);


  wcsprt_auxd(" timsyer", wcs->timsyer);
  wcsprt_auxd(" timrder", wcs->timrder);
  wcsprt_auxd(" timedel", wcs->timedel);
  wcsprt_auxd("timepixr", wcs->timepixr);

  wcsprintf("     obsgeo: ");
  for (int k = 0; k < 3; k++) {
    if (undefined(wcs->obsgeo[k])) {
      wcsprintf("       UNDEFINED");
    } else {
      wcsprintf(" %15.6f", wcs->obsgeo[k]);
    }
  }
  wcsprintf("\n             ");
  for (int k = 3; k < 6; k++) {
    if (undefined(wcs->obsgeo[k])) {
      wcsprintf("       UNDEFINED");
    } else {
      wcsprintf(" %15.6f", wcs->obsgeo[k]);
    }
  }
  wcsprintf("\n");

  wcsprt_auxc("obsorbit", wcs->obsorbit);
  wcsprt_auxc(" radesys", wcs->radesys);
  wcsprt_auxd(" equinox", wcs->equinox);
  wcsprt_auxc(" specsys", wcs->specsys);
  wcsprt_auxc(" ssysobs", wcs->ssysobs);
  wcsprt_auxd(" velosys", wcs->velosys);
  wcsprt_auxd(" zsource", wcs->zsource);
  wcsprt_auxc(" ssyssrc", wcs->ssyssrc);
  wcsprt_auxd(" velangl", wcs->velangl);

  // ...additional auxiliary coordinate system information.
  WCSPRINTF_PTR("        aux: ", wcs->aux, "\n");
  if (wcs->aux) {
    wcsprt_auxd("rsun_ref", wcs->aux->rsun_ref);
    wcsprt_auxd("dsun_obs", wcs->aux->dsun_obs);
    wcsprt_auxd("crln_obs", wcs->aux->crln_obs);
    wcsprt_auxd("hgln_obs", wcs->aux->hgln_obs);
    wcsprt_auxd("hglt_obs", wcs->aux->hglt_obs);

    wcsprt_auxd("a_radius", wcs->aux->a_radius);
    wcsprt_auxd("b_radius", wcs->aux->b_radius);
    wcsprt_auxd("c_radius", wcs->aux->c_radius);
    wcsprt_auxd("blon_obs", wcs->aux->blon_obs);
    wcsprt_auxd("blat_obs", wcs->aux->blat_obs);
    wcsprt_auxd("bdis_obs", wcs->aux->bdis_obs);
  }

  wcsprintf("       ntab: %d\n", wcs->ntab);
  WCSPRINTF_PTR("        tab: ", wcs->tab, "");
  if (wcs->tab != 0x0) wcsprintf("  (see below)");
  wcsprintf("\n");
  wcsprintf("       nwtb: %d\n", wcs->nwtb);
  WCSPRINTF_PTR("        wtb: ", wcs->wtb, "");
  if (wcs->wtb != 0x0) wcsprintf("  (see below)");
  wcsprintf("\n");

  // Derived values.
  wcsprintf("     lngtyp: \"%s\"\n", wcs->lngtyp);
  wcsprintf("     lattyp: \"%s\"\n", wcs->lattyp);
  wcsprintf("        lng: %d\n", wcs->lng);
  wcsprintf("        lat: %d\n", wcs->lat);
  wcsprintf("       spec: %d\n", wcs->spec);
  wcsprintf("       time: %d\n", wcs->time);
  wcsprintf("   cubeface: %d\n", wcs->cubeface);
  wcsprintf("     chksum:%12d\n", wcs->chksum);

  WCSPRINTF_PTR("      types: ", wcs->types, "\n           ");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("%5d", wcs->types[i]);
  }
  wcsprintf("\n");

  // Contained structs.
  wcsprintf("        lin: (see below)\n");
  wcsprintf("        cel: (see below)\n");
  wcsprintf("        spc: (see below)\n");

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

  // Memory management.
  wcsprintf("     m_flag: %d\n", wcs->m_flag);
  wcsprintf("    m_naxis: %d\n", wcs->m_naxis);
  WCSPRINTF_PTR("    m_crpix: ", wcs->m_crpix, "");
  if (wcs->m_crpix == wcs->crpix) wcsprintf("  (= crpix)");
  wcsprintf("\n");
  WCSPRINTF_PTR("       m_pc: ", wcs->m_pc, "");
  if (wcs->m_pc == wcs->pc) wcsprintf("  (= pc)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_cdelt: ", wcs->m_cdelt, "");
  if (wcs->m_cdelt == wcs->cdelt) wcsprintf("  (= cdelt)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_crval: ", wcs->m_crval, "");
  if (wcs->m_crval == wcs->crval) wcsprintf("  (= crval)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_cunit: ", wcs->m_cunit, "");
  if (wcs->m_cunit == wcs->cunit) wcsprintf("  (= cunit)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_ctype: ", wcs->m_ctype, "");
  if (wcs->m_ctype == wcs->ctype) wcsprintf("  (= ctype)");
  wcsprintf("\n");
  WCSPRINTF_PTR("       m_pv: ", wcs->m_pv, "");
  if (wcs->m_pv == wcs->pv) wcsprintf("  (= pv)");
  wcsprintf("\n");
  WCSPRINTF_PTR("       m_ps: ", wcs->m_ps, "");
  if (wcs->m_ps == wcs->ps) wcsprintf("  (= ps)");
  wcsprintf("\n");
  WCSPRINTF_PTR("       m_cd: ", wcs->m_cd, "");
  if (wcs->m_cd == wcs->cd) wcsprintf("  (= cd)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_crota: ", wcs->m_crota, "");
  if (wcs->m_crota == wcs->crota) wcsprintf("  (= crota)");
  wcsprintf("\n");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_colax: ", wcs->m_colax, "");
  if (wcs->m_colax == wcs->colax) wcsprintf("  (= colax)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_cname: ", wcs->m_cname, "");
  if (wcs->m_cname == wcs->cname) wcsprintf("  (= cname)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_crder: ", wcs->m_crder, "");
  if (wcs->m_crder == wcs->crder) wcsprintf("  (= crder)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_csyer: ", wcs->m_csyer, "");
  if (wcs->m_csyer == wcs->csyer) wcsprintf("  (= csyer)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_czphs: ", wcs->m_czphs, "");
  if (wcs->m_czphs == wcs->czphs) wcsprintf("  (= czphs)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_cperi: ", wcs->m_cperi, "");
  if (wcs->m_cperi == wcs->cperi) wcsprintf("  (= cperi)");
  wcsprintf("\n");
  WCSPRINTF_PTR("      m_aux: ", wcs->m_aux, "");
  if (wcs->m_aux == wcs->aux) wcsprintf("  (= aux)");
  wcsprintf("\n");
  WCSPRINTF_PTR("      m_tab: ", wcs->m_tab, "");
  if (wcs->m_tab == wcs->tab) wcsprintf("  (= tab)");
  wcsprintf("\n");
  WCSPRINTF_PTR("      m_wtb: ", wcs->m_wtb, "");
  if (wcs->m_wtb == wcs->wtb) wcsprintf("  (= wtb)");
  wcsprintf("\n");

  // Tabular transformation parameters.
  struct wtbarr *wtbp = wcs->wtb;
  if (wtbp) {
    for (int iwtb = 0; iwtb < wcs->nwtb; iwtb++, wtbp++) {
      wcsprintf("\n");
      wcsprintf("wtb[%d].*\n", iwtb);
      wcsprintf("          i: %d\n", wtbp->i);
      wcsprintf("          m: %d\n", wtbp->m);
      wcsprintf("       kind: %c\n", wtbp->kind);
      wcsprintf("     extnam: %s\n", wtbp->extnam);
      wcsprintf("     extver: %d\n", wtbp->extver);
      wcsprintf("     extlev: %d\n", wtbp->extlev);
      wcsprintf("      ttype: %s\n", wtbp->ttype);
      wcsprintf("        row: %ld\n", wtbp->row);
      wcsprintf("       ndim: %d\n", wtbp->ndim);
      WCSPRINTF_PTR("     dimlen: ", wtbp->dimlen, "\n");
      WCSPRINTF_PTR("     arrayp: ", wtbp->arrayp, "");
      if (wtbp->arrayp) {
        WCSPRINTF_PTR(" -> ", *(wtbp->arrayp), "\n");
      } else {
        wcsprintf("\n");
      }
    }
  }

  if (wcs->tab) {
    for (int itab = 0; itab < wcs->ntab; itab++) {
      wcsprintf("\n");
      wcsprintf("tab[%d].*\n", itab);
      tabprt(wcs->tab + itab);
    }
  }

  // Linear transformation parameters.
  wcsprintf("\n");
  wcsprintf("   lin.*\n");
  linprt(&(wcs->lin));

  // Celestial transformation parameters.
  wcsprintf("\n");
  wcsprintf("   cel.*\n");
  celprt(&(wcs->cel));

  // Spectral transformation parameters.
  wcsprintf("\n");
  wcsprintf("   spc.*\n");
  spcprt(&(wcs->spc));

  return 0;
}

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

int wcsperr(const struct wcsprm *wcs, const char *prefix)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (wcs->err && wcserr_prt(wcs->err, prefix) == 0) {
    linperr(&(wcs->lin), prefix);
    celperr(&(wcs->cel), prefix);
    wcserr_prt(wcs->spc.err, prefix);
    if (wcs->tab) {
      for (int itab = 0; itab < wcs->ntab; itab++) {
        wcserr_prt((wcs->tab + itab)->err, prefix);
      }
    }
  }

  return 0;
}

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

int wcsbchk(struct wcsprm *wcs, int bounds)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (abs(wcs->flag) != WCSSET) {
    int status;
    if ((status = wcsset(wcs))) return status;
  }

  wcs->cel.prj.bounds = bounds;

  return 0;
}

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

int wcsset(struct wcsprm *wcs)

{
  static const char *function = "wcsset";

  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  if (wcs->flag == -WCSSET) return 0;
  struct wcserr **err = &(wcs->err);

  // Determine axis types from CTYPEia.
  int status;
  if ((status = wcs_types(wcs))) {
    return status;
  }

  // Convert to canonical units.
  if ((status = wcs_units(wcs))) {
    return status;
  }

  int naxis = wcs->naxis;
  if (NAXMAX < naxis) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
      "naxis must not exceed %d (got %d)", NAXMAX, naxis);
  }


  // Non-linear celestial axes present?
  if (wcs->lng >= 0 && wcs->types[wcs->lng] == 2200) {
    struct celprm *wcscel = &(wcs->cel);
    celini(wcscel);

    // CRVALia, LONPOLEa, and LATPOLEa keyvalues.
    wcscel->ref[0] = wcs->crval[wcs->lng];
    wcscel->ref[1] = wcs->crval[wcs->lat];
    wcscel->ref[2] = wcs->lonpole;
    wcscel->ref[3] = wcs->latpole;

    // Do alias translation for TPU/TPV before dealing with PVi_ma.
    struct prjprm *wcsprj = &(wcscel->prj);
    strncpy(wcsprj->code, wcs->ctype[wcs->lng]+5, 3);
    wcsprj->code[3] = '\0';
    if (strncmp(wcsprj->code, "TPU", 3) == 0 ||
        strncmp(wcsprj->code, "TPV", 3) == 0) {
      // Translate the PV parameters.
      struct disprm *dis;
      if ((dis = calloc(1, sizeof(struct disprm))) == 0x0) {
        return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      }

      int ndpmax = 6 + wcs->npv;

      // Attach it to linprm.  Also inits it.
      char dpq[16];
      struct linprm *wcslin = &(wcs->lin);
      dis->flag = -1;
      if (strncmp(wcsprj->code, "TPU", 3) == 0) {
        // Prior distortion.
        lindist(1, wcslin, dis, ndpmax);
        strncpy(dpq, "DP", 16);
      } else {
        // Sequent distortion.
        lindist(2, wcslin, dis, ndpmax);
        strncpy(dpq, "DQ", 16);
      }

      // Yes, the distortion type is "TPV" even for TPU.
      strncpy(dis->dtype[wcs->lng], "TPV", 72);
      strncpy(dis->dtype[wcs->lat], "TPV", 72);

      // Keep the keywords in axis-order to aid debugging.
      struct dpkey *keyp = dis->dp;
      dis->ndp = 0;

      snprintf(dpq+2, 14, "%d", wcs->lng+1);
      dpfill(keyp++, dpq, "NAXES",  0, 0, 2, 0.0);
      dpfill(keyp++, dpq, "AXIS.1", 0, 0, 1, 0.0);
      dpfill(keyp++, dpq, "AXIS.2", 0, 0, 2, 0.0);
      dis->ndp += 3;

      // Copy distortion parameters for the longitude axis.
      for (int k = 0; k < wcs->npv; k++) {
        if (wcs->pv[k].i != wcs->lng+1) continue;
        snprintf(keyp->field, 72, "%s.TPV.%d", dpq, wcs->pv[k].m);
        dpfill(keyp++, 0x0, 0x0, 0, 1, 0, wcs->pv[k].value);
        dis->ndp++;
      }

      // Now the latitude axis.
      snprintf(dpq+2, 14, "%d", wcs->lat+1);
      dpfill(keyp++, dpq, "NAXES",  0, 0, 2, 0.0);
      dpfill(keyp++, dpq, "AXIS.1", 0, 0, 2, 0.0);
      dpfill(keyp++, dpq, "AXIS.2", 0, 0, 1, 0.0);
      dis->ndp += 3;

      for (int k = 0; k < wcs->npv; k++) {
        if (wcs->pv[k].i != wcs->lat+1) continue;
        snprintf(keyp->field, 72, "%s.TPV.%d", dpq, wcs->pv[k].m);
        dpfill(keyp++, 0x0, 0x0, 0, 1, 0, wcs->pv[k].value);
        dis->ndp++;
      }

      // Erase PVi_ma associated with the celestial axes.
      int n = 0;
      for (int k = 0; k < wcs->npv; k++) {
        int i = wcs->pv[k].i - 1;
        if (i == wcs->lng || i == wcs->lat) continue;

        wcs->pv[n].i = wcs->pv[k].i;
        wcs->pv[n].m = wcs->pv[k].m;
        wcs->pv[n].value = wcs->pv[k].value;

        n++;
      }

      wcs->npv = n;
      strncpy(wcsprj->code, "TAN", 4);

      // As the PVi_ma have now been erased, ctype must be reset to prevent
      // this translation from re-occurring if wcsset() is called again.
      strncpy(wcs->ctype[wcs->lng]+5, "TAN", 4);
      strncpy(wcs->ctype[wcs->lat]+5, "TAN", 4);

    } else if (strncmp(wcsprj->code, "TNX", 3) == 0) {
      // The WAT distortion should already have been encoded in disseq.
      strncpy(wcsprj->code, "TAN", 4);
      strncpy(wcs->ctype[wcs->lng]+5, "TAN", 4);
      strncpy(wcs->ctype[wcs->lat]+5, "TAN", 4);

    } else if (strncmp(wcsprj->code, "ZPX", 3) == 0) {
      // The WAT distortion should already have been encoded in disseq.
      strncpy(wcsprj->code, "ZPN", 4);
      strncpy(wcs->ctype[wcs->lng]+5, "ZPN", 4);
      strncpy(wcs->ctype[wcs->lat]+5, "ZPN", 4);
    }

    // PVi_ma keyvalues.
    for (int k = 0; k < wcs->npv; k++) {
      if (wcs->pv[k].i == 0) {
        // From a PROJPn keyword.
        wcs->pv[k].i = wcs->lat + 1;
      }

      int i = wcs->pv[k].i - 1;
      int m = wcs->pv[k].m;

      if (i == wcs->lat) {
        // PVi_ma associated with latitude axis.
        if (m < 30) {
          wcsprj->pv[m] = wcs->pv[k].value;
        }

      } else if (i == wcs->lng) {
        // PVi_ma associated with longitude axis.
        switch (m) {
        case 0:
          wcscel->offset = (wcs->pv[k].value != 0.0);
          break;
        case 1:
          wcscel->phi0   = wcs->pv[k].value;
          break;
        case 2:
          wcscel->theta0 = wcs->pv[k].value;
          break;
        case 3:
          // If present, overrides LONPOLEa.
          wcscel->ref[2] = wcs->pv[k].value;
          break;
        case 4:
          // If present, overrides LATPOLEa.
          wcscel->ref[3] = wcs->pv[k].value;
          break;
        default:
          return wcserr_set(WCSERR_SET(WCSERR_BAD_COORD_TRANS),
            "PV%i_%i%s: Unrecognized coordinate transformation parameter",
            i+1, m, wcs->alt);
          break;
        }
      }
    }

    // Do simple alias translations.
    if (strncmp(wcs->ctype[wcs->lng]+5, "GLS", 3) == 0) {
      wcscel->offset = 1;
      wcscel->phi0   = 0.0;
      wcscel->theta0 = wcs->crval[wcs->lat];
      strncpy(wcsprj->code, "SFL", 4);

    } else if (strncmp(wcs->ctype[wcs->lng]+5, "NCP", 3) == 0) {
      // Convert NCP to SIN.
      if (wcscel->ref[1] == 0.0) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
          "Invalid projection: NCP blows up on the equator");
      }

      strncpy(wcsprj->code, "SIN", 4);
      wcsprj->pv[1] = 0.0;
      wcsprj->pv[2] = cosd(wcscel->ref[1])/sind(wcscel->ref[1]);
    }

    // Initialize the celestial transformation routines.
    wcsprj->r0 = 0.0;
    wcscel->flag = 0;
    if ((status = celset(wcscel))) {
      return wcserr_set(WCS_ERRMSG(wcs_celerr[status]));
    }

    // Update LONPOLE, LATPOLE, and PVi_ma keyvalues.
    wcs->lonpole = wcscel->ref[2];
    wcs->latpole = wcscel->ref[3];

    for (int k = 0; k < wcs->npv; k++) {
      int i = wcs->pv[k].i - 1;
      int m = wcs->pv[k].m;

      if (i == wcs->lng) {
        switch (m) {
        case 1:
          wcs->pv[k].value = wcscel->phi0;
          break;
        case 2:
          wcs->pv[k].value = wcscel->theta0;
          break;
        case 3:
          wcs->pv[k].value = wcscel->ref[2];
          break;
        case 4:
          wcs->pv[k].value = wcscel->ref[3];
          break;
        default:
          // Ignore it.
          break;
        }
      }
    }
  }


  // Non-linear spectral axis present?
  if (wcs->spec >= 0 && wcs->types[wcs->spec] == 3300) {
    char scode[4], stype[5];
    struct spcprm *wcsspc = &(wcs->spc);
    spcini(wcsspc);
    if ((status = spctype(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0,
                          0x0, 0x0, err))) {
      return status;
    }
    strncpy(wcsspc->type, stype, 8);
    strncpy(wcsspc->code, scode, 4);

    // CRVALia, RESTFRQa, and RESTWAVa keyvalues.
    wcsspc->crval = wcs->crval[wcs->spec];
    wcsspc->restfrq = wcs->restfrq;
    wcsspc->restwav = wcs->restwav;

    // PVi_ma keyvalues.
    for (int k = 0; k < wcs->npv; k++) {
      int i = wcs->pv[k].i - 1;
      int m = wcs->pv[k].m;

      if (i == wcs->spec) {
        // PVi_ma associated with grism axis.
        if (m < 7) {
          wcsspc->pv[m] = wcs->pv[k].value;
        }
      }
    }

    // Initialize the spectral transformation routines.
    wcsspc->flag = 0;
    if ((status = spcset(wcsspc))) {
      return wcserr_set(WCS_ERRMSG(wcs_spcerr[status]));
    }
  }


  // Tabular axes present?
  for (int itab = 0; itab < wcs->ntab; itab++) {
    wcs->tab[itab].flag = 0;
    if ((status = tabset(wcs->tab + itab))) {
      return wcserr_set(WCS_ERRMSG(wcs_taberr[status]));
    }
  }


  // Initialize the linear transformation.
  wcs->altlin &= 15;
  if (wcs->altlin > 1 && !(wcs->altlin & 1)) {
    double *pc = wcs->pc;

    if ((wcs->altlin & 2) && !(wcs->altlin & 8)) {
      // Copy CDi_ja to PCi_ja and reset CDELTia.
      if (!wcs->cd) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
          "ALTLIN == %d but CDij absent", wcs->altlin);
      }

      double *cd = wcs->cd;
      for (int i = 0; i < naxis; i++) {
        for (int j = 0; j < naxis; j++) {
          *(pc++) = *(cd++);
        }
        wcs->cdelt[i] = 1.0;
      }

    } else if (wcs->altlin & 4) {
      // Construct PCi_ja from CROTAia.
      if (!wcs->crota) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
          "ALTLIN == %d but CROTAj absent", wcs->altlin);
      }

      ptrdiff_t i, j;
      if ((i = wcs->lng) >= 0 && (j = wcs->lat) >= 0) {
        double rho = wcs->crota[j];

        if (wcs->cdelt[i] == 0.0) {
          return wcserr_set(WCSERR_SET(WCSERR_SINGULAR_MTX),
            "Singular transformation matrix, CDELT%d is zero", i+1);
        }
        double lambda = wcs->cdelt[j]/wcs->cdelt[i];

        *(pc + i*naxis + i) = *(pc + j*naxis + j) = cosd(rho);
        *(pc + i*naxis + j) = *(pc + j*naxis + i) = sind(rho);
        *(pc + i*naxis + j) *= -lambda;
        *(pc + j*naxis + i) /=  lambda;
      }
    }
  }

  wcs->lin.crpix = wcs->crpix;
  wcs->lin.pc    = wcs->pc;
  wcs->lin.cdelt = wcs->cdelt;
  wcs->lin.flag  = 0;
  if ((status = linset(&(wcs->lin)))) {
    return wcserr_set(WCS_ERRMSG(wcs_linerr[status]));
  }


  // Set defaults for radesys and equinox for equatorial or ecliptic.
  if (strcmp(wcs->lngtyp, "RA")   == 0 ||
      strcmp(wcs->lngtyp, "ELON") == 0 ||
      strcmp(wcs->lngtyp, "HLON") == 0) {
    if (wcs->radesys[0] == '\0') {
      if (undefined(wcs->equinox)) {
        strncpy(wcs->radesys, "ICRS", 72);
      } else if (wcs->equinox < 1984.0) {
        strncpy(wcs->radesys, "FK4", 72);
      } else {
        strncpy(wcs->radesys, "FK5", 72);
      }

    } else if (strcmp(wcs->radesys, "ICRS")  == 0 ||
               strcmp(wcs->radesys, "GAPPT") == 0) {
      // Equinox is not applicable for these coordinate systems.
      wcs->equinox = UNDEFINED;

    } else if (undefined(wcs->equinox)) {
      if (strcmp(wcs->radesys, "FK5") == 0) {
        wcs->equinox = 2000.0;
      } else if (strcmp(wcs->radesys, "FK4") == 0 ||
                 strcmp(wcs->radesys, "FK4-NO-E") == 0) {
        wcs->equinox = 1950.0;
      }
    }

  } else {
    // No celestial axes, ensure that radesys and equinox are unset.
    memset(wcs->radesys, 0, 72);
    wcs->equinox = UNDEFINED;
  }


  // Strip off trailing blanks and null-fill auxiliary string members.
  if (wcs->alt[0] == '\0') wcs->alt[0] = ' ';
  memset(wcs->alt+1, '\0', 3);

  if (wcs->cname) {
    for (int i = 0; i < naxis; i++) {
      wcsutil_null_fill(72, wcs->cname[i]);
    }
  }
  wcsutil_null_fill(72, wcs->wcsname);
  wcsutil_null_fill(72, wcs->timesys);
  wcsutil_null_fill(72, wcs->trefpos);
  wcsutil_null_fill(72, wcs->trefdir);
  wcsutil_null_fill(72, wcs->plephem);
  wcsutil_null_fill(72, wcs->timeunit);
  wcsutil_null_fill(72, wcs->dateref);
  wcsutil_null_fill(72, wcs->dateobs);
  wcsutil_null_fill(72, wcs->datebeg);
  wcsutil_null_fill(72, wcs->dateavg);
  wcsutil_null_fill(72, wcs->dateend);
  wcsutil_null_fill(72, wcs->obsorbit);
  wcsutil_null_fill(72, wcs->radesys);
  wcsutil_null_fill(72, wcs->specsys);
  wcsutil_null_fill(72, wcs->ssysobs);
  wcsutil_null_fill(72, wcs->ssyssrc);

  // MJDREF defaults to zero if no reference date keywords were defined.
  if (wcs->dateref[0] == '\0') {
    if (undefined(wcs->mjdref[0])) {
      wcs->mjdref[0] = 0.0;
    }
    if (undefined(wcs->mjdref[1])) {
      wcs->mjdref[1] = 0.0;
    }
  }

  // Compute and store the checksum.
  wcs->chksum = wcs_chksum(wcs);

  wcs->flag = (wcs->flag == 1) ? -WCSSET : WCSSET;

  return 0;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int wcs_types(struct wcsprm *wcs)

{
  static const char *function = "wcs_types";

  const int  nalias = 6;
  const char aliases [6][4] = {"NCP", "GLS", "TPU", "TPV", "TNX", "ZPX"};

  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  // Parse the CTYPEia keyvalues.
  char pcode[4], requir[16];
  pcode[0]  = '\0';
  requir[0] = '\0';
  wcs->lng  = -1;
  wcs->lat  = -1;
  wcs->spec = -1;
  wcs->time = -1;
  wcs->cubeface = -1;

  const char *alt = "";
  if (*(wcs->alt) != ' ') alt = wcs->alt;


  int naxis = wcs->naxis;
  if (wcs->types) free(wcs->types);
  if ((wcs->types = calloc(naxis, sizeof(int))) == 0x0) {
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
  }

  int *ndx = 0x0;
  for (int i = 0; i < naxis; i++) {
    // Null fill.
    wcsutil_null_fill(72, wcs->ctype[i]);

    char ctypei[16];
    strncpy(ctypei, wcs->ctype[i], 15);
    ctypei[15] = '\0';

    // Check for early Paper IV syntax (e.g. '-SIP' used by Spitzer).
    if (strlen(ctypei) == 12 && ctypei[8] == '-') {
      // Excise the "4-3-3" or "8-3"-form distortion code.
      ctypei[8] = '\0';

      // Remove trailing dashes from "8-3"-form codes.
      for (int j = 7; j > 0; j--) {
        if (ctypei[j] != '-') break;
        ctypei[j] = '\0';
      }
    }

    // Logarithmic or tabular axis?
    wcs->types[i] = 0;
    if (strcmp(ctypei+4, "-LOG") == 0) {
      // Logarithmic axis.
      wcs->types[i] = 400;

    } else if (strcmp(ctypei+4, "-TAB") == 0) {
      // Tabular axis.
      wcs->types[i] = 500;
    }

    if (wcs->types[i]) {
      // Could have -LOG or -TAB with celestial or spectral types.
      ctypei[4] = '\0';

      // Take care of things like 'FREQ-LOG' or 'RA---TAB'.
      for (int j = 3; j >= 0; j--) {
        if (ctypei[j] != '-') break;
        ctypei[j] = '\0';
      }
    }

    // Translate AIPS spectral types for spctyp().
    char specsys[9];
    if (spcaips(ctypei, wcs->velref, ctypei, specsys) == 0) {
      strncpy(wcs->ctype[i], ctypei, 72);
      if (wcs->specsys[0] == '\0') strncpy(wcs->specsys, specsys, 72);
    }

    // Process linear axes.
    if (!(strlen(ctypei) == 8 && ctypei[4] == '-')) {
      // Identify Stokes, celestial, spectral, and time types.
      if (strcmp(ctypei, "STOKES") == 0) {
        // STOKES axis.
        wcs->types[i] = 1100;

      } else if (strcmp(ctypei, "RA")  == 0 ||
        strcmp(ctypei+1, "LON") == 0 ||
        strcmp(ctypei+2, "LN")  == 0) {
        // Longitude axis.
        wcs->types[i] += 2000;
        if (wcs->lng < 0) {
          wcs->lng = i;
          strncpy(wcs->lngtyp, ctypei, 8);
        }

      } else if (strcmp(ctypei,   "DEC") == 0 ||
                 strcmp(ctypei+1, "LAT") == 0 ||
                 strcmp(ctypei+2, "LT")  == 0) {
        // Latitude axis.
        wcs->types[i] += 2001;
        if (wcs->lat < 0) {
          wcs->lat = i;
          strncpy(wcs->lattyp, ctypei, 8);
        }

      } else if (strcmp(ctypei, "CUBEFACE") == 0) {
        // CUBEFACE axis.
        if (wcs->cubeface == -1) {
          wcs->types[i] = 2102;
          wcs->cubeface = i;
        } else {
          // Multiple CUBEFACE axes!
          return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
            "Multiple CUBEFACE axes (in CTYPE%d%.1s and CTYPE%d%.1s)",
            wcs->cubeface+1, alt, i+1, alt);
        }

      } else if (spctyp(ctypei, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
        // Spectral axis.
        if (wcs->spec < 0) wcs->spec = i;
        wcs->types[i] += 3000;

      } else if (time_type(ctypei)) {
        // Time axis.
        if (wcs->time < 0) wcs->time = i;
        wcs->types[i] += 4000;
      }

      continue;
    }


    // CTYPEia is in "4-3" form; is it a recognized spectral type?
    char scode[4];
    if (spctyp(ctypei, 0x0, scode, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
      // Non-linear spectral axis found.
      wcs->types[i] = 3300;

      // Check uniqueness.
      if (wcs->spec >= 0) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Multiple spectral axes (in CTYPE%d%.1s and CTYPE%d%.1s)",
          wcs->spec+1, alt, i+1, alt);
      }

      wcs->spec = i;

      continue;
    }


    // Is it a recognized celestial projection?
    int j;
    for (j = 0; j < prj_ncode; j++) {
      if (strncmp(ctypei+5, prj_codes[j], 3) == 0) break;
    }

    if (j == prj_ncode) {
      // Not a standard projection code, maybe it's an alias.
      for (j = 0; j < nalias; j++) {
        if (strncmp(ctypei+5, aliases[j], 3) == 0) break;
      }

      if (j == nalias) {
        // Not a recognized algorithm code of any type.
        wcs->types[i] = -1;
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Unrecognized projection code (%s in CTYPE%d%.1s)",
          ctypei+5, i+1, alt);
      }
    }

    // Parse the celestial axis type.
    wcs->types[i] = 2200;
    if (*pcode == '\0') {
      // The first of the two celestial axes.
      snprintf(pcode, 4, "%.3s", ctypei+5);

      if (strncmp(ctypei, "RA--", 4) == 0) {
        wcs->lng = i;
        strncpy(wcs->lngtyp, "RA", 8);
        strncpy(wcs->lattyp, "DEC", 8);
        ndx = &wcs->lat;
        snprintf(requir, 16, "DEC--%s", pcode);
      } else if (strncmp(ctypei, "DEC-", 4) == 0) {
        wcs->lat = i;
        strncpy(wcs->lngtyp, "RA", 8);
        strncpy(wcs->lattyp, "DEC", 8);
        ndx = &wcs->lng;
        snprintf(requir, 16, "RA---%s", pcode);
      } else if (strncmp(ctypei+1, "LON", 3) == 0) {
        wcs->lng = i;
        snprintf(wcs->lngtyp, 8, "%cLON", ctypei[0]);
        snprintf(wcs->lattyp, 8, "%cLAT", ctypei[0]);
        ndx = &wcs->lat;
        snprintf(requir, 16, "%s-%s", wcs->lattyp, pcode);
      } else if (strncmp(ctypei+1, "LAT", 3) == 0) {
        wcs->lat = i;
        snprintf(wcs->lngtyp, 8, "%cLON", ctypei[0]);
        snprintf(wcs->lattyp, 8, "%cLAT", ctypei[0]);
        ndx = &wcs->lng;
        snprintf(requir, 16, "%s-%s", wcs->lngtyp, pcode);
      } else if (strncmp(ctypei+2, "LN", 2) == 0) {
        wcs->lng = i;
        snprintf(wcs->lngtyp, 8, "%c%cLN", ctypei[0], ctypei[1]);
        snprintf(wcs->lattyp, 8, "%c%cLT", ctypei[0], ctypei[1]);
        ndx = &wcs->lat;
        snprintf(requir, 16, "%s-%s", wcs->lattyp, pcode);
      } else if (strncmp(ctypei+2, "LT", 2) == 0) {
        wcs->lat = i;
        snprintf(wcs->lngtyp, 8, "%c%cLN", ctypei[0], ctypei[1]);
        snprintf(wcs->lattyp, 8, "%c%cLT", ctypei[0], ctypei[1]);
        ndx = &wcs->lng;
        snprintf(requir, 16, "%s-%s", wcs->lngtyp, pcode);
      } else {
        // Unrecognized celestial type.
        wcs->types[i] = -1;

        wcs->lng = -1;
        wcs->lat = -1;
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Unrecognized celestial type (%5s in CTYPE%d%.1s)",
          ctypei, i+1, alt);
      }

      if (wcs->lat >= 0) wcs->types[i]++;

    } else {
      // Looking for the complementary celestial axis.
      if (wcs->lat < 0) wcs->types[i]++;

      if (strncmp(ctypei, requir, 8) != 0) {
        // Inconsistent projection types.
        wcs->lng = -1;
        wcs->lat = -1;
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE), "Inconsistent "
          "projection types (expected %s, got %s in CTYPE%d%.1s)", requir,
          ctypei, i+1, alt);
      }

      *ndx = i;
      requir[0] = '\0';
    }
  }

  // Do we have a complementary pair of celestial axes?
  if (strcmp(requir, "") != 0) {
    // Unmatched celestial axis.
    wcs->lng = -1;
    wcs->lat = -1;
    return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
      "Unmatched celestial axes");
  }

  // Table group numbers.
  for (int j = 0; j < wcs->ntab; j++) {
    for (int m = 0; m < wcs->tab[j].M; m++) {
      // Get image axis number.
      int i = wcs->tab[j].map[m];

      int type = (wcs->types[i] / 100) % 10;
      if (type != 5) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Table parameters set for non-table axis type");
      }
      wcs->types[i] += 10 * j;
    }
  }

  return 0;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int time_type(const char *ctype)

{
  // Is it a recognised time system as listed in Table 2 of WCS Paper VII?
  if (strncmp(ctype, "TIME", 4) == 0) return time_code(ctype, 4);
  if (strncmp(ctype, "UTC",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TAI",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "IAT",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TT",   2) == 0) return time_code(ctype, 2);
  if (strncmp(ctype, "TDB",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TDT",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "GPS",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TCB",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TCG",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "GMT",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "UT1",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "UT",   2) == 0) return time_code(ctype, 2);
  if (strncmp(ctype, "ET",   2) == 0) return time_code(ctype, 2);
  if (strncmp(ctype, "LOCAL",5) == 0) return 1;

  return 0;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int time_code(const char *ctype, int nc)

{
  // If no algorithm code then we're finished.
  if (*(ctype+nc) == '\0') return 1;

  // Check the correct number of hyphens for things like "TT---TAB".
  while (nc < 4) {
    if (*(ctype+nc) != '-') return 0;
    nc++;
  }

  // Is it a code applicable to time-like axes?
  const char *code = ctype + 4;
  if (*code == '-') {
    if (strcmp(code, "-LOG") == 0) return 1;
    if (strcmp(code, "-TAB") == 0) return 1;
  }

  return 0;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int wcs_units(struct wcsprm *wcs)

{
  static const char *function = "wcs_units";

  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  int naxis = wcs->naxis;
  for (int i = 0; i < naxis; i++) {
    // Squeeze out trailing blanks.
    wcsutil_null_fill(72, wcs->cunit[i]);

    // Use types set by wcs_types().
    char ctype[9], units[16];
    switch (wcs->types[i]/1000) {
    case 2:
      // Celestial axis.
      strncpy(units, "deg", 16);
      break;

    case 3:
      // Spectral axis.
      strncpy(ctype, wcs->ctype[i], 9);
      ctype[8] = '\0';
      spctyp(ctype, 0x0, 0x0, 0x0, units, 0x0, 0x0, 0x0);
      break;

    default:
      continue;
    }

    // Tabular axis, CDELTia and CRVALia relate to indices.
    if ((wcs->types[i]/100)%10 == 5) {
      continue;
    }

    if (wcs->cunit[i][0]) {
      double scale, offset, power;
      struct wcserr *uniterr;
      if (wcsunitse(wcs->cunit[i], units, &scale, &offset, &power,
                    &uniterr)) {
        if (uniterr) {
          // uniterr will not be set if wcserr is not enabled.
          wcserr_set(WCSERR_SET(WCSERR_BAD_COORD_TRANS),
            "In CUNIT%d%.1s: %s", i+1, (*wcs->alt)?wcs->alt:"", uniterr->msg);
          free(uniterr);
        }
        return WCSERR_BAD_COORD_TRANS;
      }

      if (scale != 1.0) {
        wcs->cdelt[i] *= scale;
        wcs->crval[i] *= scale;

        if (wcs->cd) {
          for (int j = 0; j < naxis; j++) {
            ptrdiff_t cdij = i*naxis + j;
            *(wcs->cd + cdij) *= scale;
          }
        }

        strncpy(wcs->cunit[i], units, 72);
      }

    } else {
      strncpy(wcs->cunit[i], units, 72);
    }
  }

  return 0;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int wcs_chksum(const struct wcsprm *wcs)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  size_t  naxis = wcs->naxis;
  size_t    szi = sizeof(int);
  size_t    szd = sizeof(double);
  size_t nszc72 = naxis * sizeof(char [72]);
  size_t   nszd = naxis *  szd;
  size_t  nnszd = naxis * nszd;

  int chksum = 0;

  // The checksum is computed incrementally - the result from one invokation
  // forms the starting value for the next one.
  chksum = wcs_fletcher32(chksum, &wcs->naxis,   szi);
  chksum = wcs_fletcher32(chksum, wcs->crpix,   nszd);
  chksum = wcs_fletcher32(chksum, wcs->pc,     nnszd);
  chksum = wcs_fletcher32(chksum, wcs->cdelt,   nszd);
  chksum = wcs_fletcher32(chksum, wcs->crval,   nszd);
  chksum = wcs_fletcher32(chksum, wcs->cunit,   nszc72);
  chksum = wcs_fletcher32(chksum, wcs->ctype,   nszc72);
  chksum = wcs_fletcher32(chksum, &wcs->lonpole, szd);
  chksum = wcs_fletcher32(chksum, &wcs->latpole, szd);
  chksum = wcs_fletcher32(chksum, &wcs->restfrq, szd);
  chksum = wcs_fletcher32(chksum, &wcs->restwav, szd);
  chksum = wcs_fletcher32(chksum, &wcs->npv,     szi);

  if (wcs->pv) {
    size_t nszpv = wcs->npv * sizeof(struct pvcard);
    chksum = wcs_fletcher32(chksum, wcs->pv, nszpv);
  }

  chksum = wcs_fletcher32(chksum, &wcs->nps, szi);

  if (wcs->ps) {
    size_t nszps = wcs->nps * sizeof(struct pscard);
    chksum = wcs_fletcher32(chksum, wcs->ps, nszps);
  }

  if (wcs->cd) {
    chksum = wcs_fletcher32(chksum, wcs->cd, nnszd);
  }

  if (wcs->crota) {
    chksum = wcs_fletcher32(chksum, wcs->crota, nszd);
  }

  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->altlin), szi);
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->ntab), szi);
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->nwtb), szi);
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->tab),
                          sizeof(struct tabprm *));
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->wtb),
                          sizeof(struct wtbarr *));

  return chksum;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

// Compute the Fletcher-32 checksum for a sequence of bytes.  The algorithm is
// described in https://en.wikipedia.org/wiki/Fletcher's_checksum.
//
// Given:
//   chksum    int      Checksum from a previous invokation, forming the
//                      starting value for this one.
//
//   data      const void *
//                      Data array, treated as an array of uint16_t.
//
//   len       size_t   Length of the data array in bytes.  Must be even and
//                      between 0 and 259200 inclusive (no checks are made).
//
// Function return value:
//             int      Fletcher-32 checksum.

static int wcs_fletcher32(int chksum, const void *data, size_t len)

{
  const uint16_t *datap = (const uint16_t *)data;

  uint32_t c0 = ((uint32_t)chksum & 65535);
  uint32_t c1 = ((uint32_t)chksum >> 16);

  while (len) {
    c0 += *datap++;
    c1 += c0;
    len -= 2;
  }

  c0 %= 65535;
  c1 %= 65535;

  return (int)(c1 << 16 | c0);
}

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

int wcsp2s(
  struct wcsprm *wcs,
  int ncoord,
  int nelem,
  const double pixcrd[],
  double imgcrd[],
  double phi[],
  double theta[],
  double world[],
  int stat[])

{
  static const char *function = "wcsp2s";

  // Initialize if required.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  int status = 0;
  if (abs(wcs->flag) != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  // Sanity check.
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
      "ncoord and/or nelem inconsistent with the wcsprm");
  }


  // Initialize status vectors.
  int *istatp;
  if ((istatp = calloc(ncoord, sizeof(int))) == 0x0) {
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
  }

  stat[0] = 0;
  wcsutil_setAli(ncoord, 1, stat);


  // Apply pixel-to-world linear transformation.
  struct linprm *lin = &(wcs->lin);
  if (!(lin->dispre || lin->disseq)) {
    // No distortions present, do vector call.
    int istat = linp2x(lin, ncoord, nelem, pixcrd, imgcrd);
    if (istat) {
      // If one fails then all fail.
      status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
      goto cleanup;
    }

  } else {
    // Distortions present, get the status return for each coordinate.
    int disaxes = 0;

    const double *pix = pixcrd;
    double *img = imgcrd;
    int *statp = stat;
    for (int k = 0 ; k < ncoord; k++, pix += nelem, img += nelem, statp++) {
      int istat = linp2x(lin, 1, nelem, pix, img);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
        if (status != WCSERR_BAD_PIX) {
          goto cleanup;
        }

        if (disaxes == 0) {
          // Which axes have distortions?
          struct disprm *dispre = lin->dispre;
          struct disprm *disseq = lin->disseq;
          for (int i = 0; i < wcs->naxis; i++) {
            if ((dispre && dispre->disp2x[i]) ||
                (disseq && disseq->disp2x[i])) {
              disaxes |= (1 << i);
            }
          }

          if (disaxes == 0) {
            // Shouldn't happen.
            disaxes = (2 << wcs->naxis) - 1;
          }
        }

        // WCSERR_BAD_PIX stat[] vector accounting.
        *statp = disaxes;
      }
    }
  }


  // Convert intermediate world coordinates to world coordinates.
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  for (int i = 0; i < wcs->naxis; i++) {
    // Extract the second digit of the axis type code.
    int type = (wcs->types[i] / 100) % 10;

    double *img, *wrl;
    if (type <= 1) {
      // Linear or quantized coordinate axis.
      img = imgcrd + i;
      wrl = world  + i;
      double crvali = wcs->crval[i];
      for (int k = 0; k < ncoord; k++) {
        *wrl = *img + crvali;
        img += nelem;
        wrl += nelem;
      }

    } else if (wcs->types[i] == 2200) {
      // Convert celestial coordinates; do we have a CUBEFACE axis?
      if (wcs->cubeface != -1) {
        // Separation between faces.
        double offset;
        if (wcsprj->r0 == 0.0) {
          offset = 90.0;
        } else {
          offset = wcsprj->r0*PI/2.0;
        }

        // Lay out faces in a plane.
        img = imgcrd;
        int *statp = stat;
        int bits = (1 << i) | (1 << wcs->lat);
        for (int k = 0; k < ncoord; k++, statp++) {
          int face = (int)(*(img+wcs->cubeface) + 0.5);
          if (fabs(*(img+wcs->cubeface) - face) > 1e-10) {
            *statp |= bits;
            status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));

          } else {
            *statp = 0;

            switch (face) {
            case 0:
              *(img+wcs->lat) += offset;
              break;
            case 1:
              break;
            case 2:
              *(img+i) += offset;
              break;
            case 3:
              *(img+i) += offset*2;
              break;
            case 4:
              *(img+i) += offset*3;
              break;
            case 5:
              *(img+wcs->lat) -= offset;
              break;
            default:
              *statp |= bits;
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
              break;
            }
          }

          img += nelem;
        }
      }

      // Check for constant x and/or y.
      int iso_x = 0;
      int iso_y = 0;
      int nx = ncoord;
      int ny = 0;

      if (ncoord > 1) {
        if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
          nx = 1;
          ny = ncoord;
        }
        if ((iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat))) {
          ny = 1;
        }
      }

      // Transform projection plane coordinates to celestial coordinates.
      int istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                         imgcrd+wcs->lat, phi, theta, world+i,
                         world+wcs->lat, istatp);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
        if (status != WCSERR_BAD_PIX) {
          goto cleanup;
        }
      }

      // If x and y were both constant, replicate values.
      if (iso_x && iso_y) {
        wcsutil_setAll(ncoord, nelem, world+i);
        wcsutil_setAll(ncoord, nelem, world+wcs->lat);
        wcsutil_setAll(ncoord, 1, phi);
        wcsutil_setAll(ncoord, 1, theta);
        wcsutil_setAli(ncoord, 1, istatp);
      }

      // WCSERR_BAD_PIX stat[] vector accounting.
      if (istat) {
        int bits = (1 << i) | (1 << wcs->lat);
        wcsutil_setBit(ncoord, istatp, bits, stat);
      }

    } else if (type == 3 || type == 4) {
      // Spectral and logarithmic coordinates; check for constant x.
      int iso_x = 0;
      int nx = ncoord;

      if (ncoord > 1) {
        if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
          nx = 1;
        }
      }

      int istat = 0;
      if (wcs->types[i] == 3300) {
        // Spectral coordinates.
        istat = spcx2s(&(wcs->spc), nx, nelem, nelem, imgcrd+i, world+i,
                       istatp);
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_spcerr[istat]));
          if (status != WCSERR_BAD_PIX) {
            goto cleanup;
          }
        }
      } else if (type == 4) {
        // Logarithmic coordinates.
        istat = logx2s(wcs->crval[i], nx, nelem, nelem, imgcrd+i, world+i,
                       istatp);
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_logerr[istat]));
          if (status != WCSERR_BAD_PIX) {
            goto cleanup;
          }
        }
      }

      // If x was constant, replicate values.
      if (iso_x) {
        wcsutil_setAll(ncoord, nelem, world+i);
        wcsutil_setAli(ncoord, 1, istatp);
      }

      // WCSERR_BAD_PIX stat[] vector accounting.
      if (istat) {
        wcsutil_setBit(ncoord, istatp, 1 << i, stat);
      }
    }
  }


  // Do tabular coordinates.
  for (int itab = 0; itab < wcs->ntab; itab++) {
    int istat = tabx2s(wcs->tab + itab, ncoord, nelem, imgcrd, world, istatp);

    if (istat) {
      status = wcserr_set(WCS_ERRMSG(wcs_taberr[istat]));
      if (status != WCSERR_BAD_PIX) {
        goto cleanup;
      }

      // WCSERR_BAD_PIX stat[] vector accounting.
      int bits = 0;
      for (int m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
      }
      wcsutil_setBit(ncoord, istatp, bits, stat);
    }
  }


  // Zero the unused world coordinate elements.
  for (int i = wcs->naxis; i < nelem; i++) {
    world[i] = 0.0;
    wcsutil_setAll(ncoord, nelem, world+i);
  }

cleanup:
  free(istatp);
  return status;
}

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

int wcss2p(
  struct wcsprm* wcs,
  int ncoord,
  int nelem,
  const double world[],
  double phi[],
  double theta[],
  double imgcrd[],
  double pixcrd[],
  int stat[])

{
  static const char *function = "wcss2p";

  // Initialize if required.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  int status = 0;
  if (abs(wcs->flag) != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  // Sanity check.
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
      "ncoord and/or nelem inconsistent with the wcsprm");
  }

  // Initialize status vectors.
  int *istatp;
  if ((istatp = calloc(ncoord, sizeof(int))) == 0x0) {
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
  }

  stat[0] = 0;
  wcsutil_setAli(ncoord, 1, stat);


  // Convert world coordinates to intermediate world coordinates.
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  for (int i = 0; i < wcs->naxis; i++) {
    // Extract the second digit of the axis type code.
    int type = (wcs->types[i] / 100) % 10;

    if (type <= 1) {
      // Linear or quantized coordinate axis.
      const double *wrl = world  + i;
      double *img = imgcrd + i;
      double crvali = wcs->crval[i];
      for (int k = 0; k < ncoord; k++) {
        *img = *wrl - crvali;
        wrl += nelem;
        img += nelem;
      }

    } else if (wcs->types[i] == 2200) {
      // Celestial coordinates; check for constant lng and/or lat.
      int isolng = 0;
      int isolat = 0;
      int nlng = ncoord;
      int nlat = 0;

      if (ncoord > 1) {
        if ((isolng = wcsutil_allEq(ncoord, nelem, world+i))) {
          nlng = 1;
          nlat = ncoord;
        }
        if ((isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat))) {
          nlat = 1;
        }
      }

      // Transform celestial coordinates to projection plane coordinates.
      int istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                         world+wcs->lat, phi, theta, imgcrd+i,
                         imgcrd+wcs->lat, istatp);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
        if (status != WCSERR_BAD_WORLD) {
          goto cleanup;
        }
      }

      // If lng and lat were both constant, replicate values.
      if (isolng && isolat) {
        wcsutil_setAll(ncoord, nelem, imgcrd+i);
        wcsutil_setAll(ncoord, nelem, imgcrd+wcs->lat);
        wcsutil_setAll(ncoord, 1, phi);
        wcsutil_setAll(ncoord, 1, theta);
        wcsutil_setAli(ncoord, 1, istatp);
      }

      // WCSERR_BAD_WORLD stat[] vector accounting.
      if (istat) {
        int bits = (1 << i) | (1 << wcs->lat);
        wcsutil_setBit(ncoord, istatp, bits, stat);
      }

      // Do we have a CUBEFACE axis?
      if (wcs->cubeface != -1) {
        // Separation between faces.
        double offset;
        if (wcsprj->r0 == 0.0) {
          offset = 90.0;
        } else {
          offset = wcsprj->r0*PI/2.0;
        }

        // Stack faces in a cube.
        double *img = imgcrd;
        for (int k = 0; k < ncoord; k++) {
          if (*(img+wcs->lat) < -0.5*offset) {
            *(img+wcs->lat) += offset;
            *(img+wcs->cubeface) = 5.0;
          } else if (*(img+wcs->lat) > 0.5*offset) {
            *(img+wcs->lat) -= offset;
            *(img+wcs->cubeface) = 0.0;
          } else if (*(img+i) > 2.5*offset) {
            *(img+i) -= 3.0*offset;
            *(img+wcs->cubeface) = 4.0;
          } else if (*(img+i) > 1.5*offset) {
            *(img+i) -= 2.0*offset;
            *(img+wcs->cubeface) = 3.0;
          } else if (*(img+i) > 0.5*offset) {
            *(img+i) -= offset;
            *(img+wcs->cubeface) = 2.0;
          } else {
            *(img+wcs->cubeface) = 1.0;
          }

          img += nelem;
        }
      }

    } else if (type == 3 || type == 4) {
      // Spectral and logarithmic coordinates; check for constancy.
      int isospec = 0;
      int nwrld = ncoord;

      if (ncoord > 1) {
        if ((isospec = wcsutil_allEq(ncoord, nelem, world+i))) {
          nwrld = 1;
        }
      }

      int istat = 0;
      if (wcs->types[i] == 3300) {
        // Spectral coordinates.
        istat = spcs2x(&(wcs->spc), nwrld, nelem, nelem, world+i,
                       imgcrd+i, istatp);
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_spcerr[istat]));
          if (status != WCSERR_BAD_WORLD) {
            goto cleanup;
          }
        }
      } else if (type == 4) {
        // Logarithmic coordinates.
        istat = logs2x(wcs->crval[i], nwrld, nelem, nelem, world+i,
                       imgcrd+i, istatp);
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_logerr[istat]));
          if (status != WCSERR_BAD_WORLD) {
            goto cleanup;
          }
        }
      }

      // If constant, replicate values.
      if (isospec) {
        wcsutil_setAll(ncoord, nelem, imgcrd+i);
        wcsutil_setAli(ncoord, 1, istatp);
      }

      // WCSERR_BAD_WORLD stat[] vector accounting.
      if (istat) {
        wcsutil_setBit(ncoord, istatp, 1 << i, stat);
      }
    }
  }


  // Do tabular coordinates.
  for (int itab = 0; itab < wcs->ntab; itab++) {
    int istat = tabs2x(wcs->tab + itab, ncoord, nelem, world, imgcrd, istatp);

    if (istat) {
      status = wcserr_set(WCS_ERRMSG(wcs_taberr[istat]));

      if (status != WCSERR_BAD_WORLD) {
        goto cleanup;
      }

      int bits = 0;
      for (int m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
      }
      wcsutil_setBit(ncoord, istatp, bits, stat);
    }
  }


  // Zero the unused intermediate world coordinate elements.
  for (int i = wcs->naxis; i < nelem; i++) {
    imgcrd[i] = 0.0;
    wcsutil_setAll(ncoord, nelem, imgcrd+i);
  }


  // Apply world-to-pixel linear transformation.
  struct linprm *lin = &(wcs->lin);
  if (!(lin->dispre || lin->disseq)) {
    // No distortions present, do vector call.
    int istat = linx2p(lin, ncoord, nelem, imgcrd, pixcrd);
    if (istat) {
      status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
      goto cleanup;
    }

  } else {
    // Distortions present, get the status return for each coordinate.
    int disaxes = 0;

    const double *img = imgcrd;
    double *pix = pixcrd;
    int *statp = stat;
    for (int k = 0 ; k < ncoord; k++, pix += nelem, img += nelem, statp++) {
      int istat = linx2p(lin, 1, nelem, img, pix);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
        if (status != WCSERR_BAD_WORLD) {
          goto cleanup;
        }

        if (disaxes == 0) {
          // Which axes have distortions?
          struct disprm *dispre = lin->dispre;
          struct disprm *disseq = lin->disseq;
          for (int i = 0; i < wcs->naxis; i++) {
            if ((dispre && dispre->disp2x[i]) ||
                (disseq && disseq->disp2x[i])) {
              disaxes |= (1 << i);
            }
          }

          if (disaxes == 0) {
            // Shouldn't happen.
            disaxes = (2 << wcs->naxis) - 1;
          }
        }

        // WCSERR_BAD_WORLD stat[] vector accounting.
        *statp = disaxes;
      }
    }
  }

cleanup:
  free(istatp);
  return status;
}

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

int wcsmix(
  struct wcsprm *wcs,
  int mixpix,
  int mixcel,
  const double vspan[2],
  double vstep,
  int viter,
  double world[],
  double phi[],
  double theta[],
  double imgcrd[],
  double pixcrd[])

{
  static const char *function = "wcsmix";

  const int niter = 60;
  const double tol  = 1.0e-10;
  const double tol2 = 100.0*tol;

  // Initialize if required.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  int status;
  if (abs(wcs->flag) != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  if (wcs->lng < 0 || wcs->lat < 0) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_SUBIMAGE),
      "Image does not have celestial axes");
  }

  double *worldlng = world + wcs->lng;
  double *worldlat = world + wcs->lat;


  // Check vspan.
  double span[2];
  if (vspan[0] <= vspan[1]) {
    span[0] = vspan[0];
    span[1] = vspan[1];
  } else {
    // Swap them.
    span[0] = vspan[1];
    span[1] = vspan[0];
  }

  // Check vstep.
  double step = fabs(vstep);
  if (step == 0.0) {
    step = (span[1] - span[0])/10.0;
    if (step > 1.0 || step == 0.0) step = 1.0;
  }

  // Check viter.
  int nstep = viter;
  if (nstep < 5) {
    nstep = 5;
  } else if (nstep > 10) {
    nstep = 10;
  }

  // Given pixel element.
  double pixmix = pixcrd[mixpix];

  // Iterate on the step size.
  for (int istep = 0; istep <= nstep; istep++) {
    if (istep) step /= 2.0;

    // Iterate on the sky coordinate between the specified range.
    if (mixcel == 1) {
      // Celestial longitude is given.

      // Check whether the solution interval is a crossing interval.
      double lat0 = span[0];
      *worldlat = lat0;
      int stat[1];
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
        return status;
      }
      double d0 = pixcrd[mixpix] - pixmix;

      double dabs = fabs(d0);
      if (dabs < tol) return 0;

      double lat1 = span[1];
      *worldlat = lat1;
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
        return status;
      }
      double d1 = pixcrd[mixpix] - pixmix;

      dabs = fabs(d1);
      if (dabs < tol) return 0;

      double lmin = lat1;
      double dmin = dabs;

      // Check for a crossing point.
      int crossed;
      double dx = 0.0;
      if (signbit(d0) != signbit(d1)) {
        crossed = 1;
        dx = d1;
      } else {
        crossed = 0;
        lat0 = span[1];
      }

      for (int retry = 0; retry < 4; retry++) {
        // Refine the solution interval.
        while (lat0 > span[0]) {
          lat0 -= step;
          if (lat0 < span[0]) lat0 = span[0];
          *worldlat = lat0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
            return status;
          }
          d0 = pixcrd[mixpix] - pixmix;

          // Check for a solution.
          dabs = fabs(d0);
          if (dabs < tol) return 0;

          // Record the point of closest approach.
          if (dabs < dmin) {
            lmin = lat0;
            dmin = dabs;
          }

          // Check for a crossing point.
          if (signbit(d0) != signbit(d1)) {
            crossed = 2;
            dx = d0;
            break;
          }

          // Advance to the next subinterval.
          lat1 = lat0;
          d1 = d0;
        }

        if (crossed) {
          // A crossing point was found.
          for (int iter = 0; iter < niter; iter++) {
            // Use regula falsi division of the interval.
            double lambda = d0/(d0-d1);
            if (lambda < 0.1) {
              lambda = 0.1;
            } else if (lambda > 0.9) {
              lambda = 0.9;
            }

            double dlat = lat1 - lat0;
            double lat = lat0 + lambda*dlat;
            *worldlat = lat;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
              return status;
            }

            // Check for a solution.
            double d = pixcrd[mixpix] - pixmix;
            dabs = fabs(d);
            if (dabs < tol) return 0;

            if (dlat < tol) {
              // An artifact of numerical imprecision.
              if (dabs < tol2) return 0;

              // Must be a discontinuity.
              break;
            }

            // Record the point of closest approach.
            if (dabs < dmin) {
              lmin = lat;
              dmin = dabs;
            }

            if (signbit(d0) == signbit(d)) {
              lat0 = lat;
              d0 = d;
            } else {
              lat1 = lat;
              d1 = d;
            }
          }

          // No convergence, must have been a discontinuity.
          if (crossed == 1) lat0 = span[1];
          lat1 = lat0;
          d1 = dx;
          crossed = 0;

        } else {
          // No crossing point; look for a tangent point.
          if (lmin == span[0]) break;
          if (lmin == span[1]) break;

          double lat = lmin;
          lat0 = lat - step;
          if (lat0 < span[0]) lat0 = span[0];
          lat1 = lat + step;
          if (lat1 > span[1]) lat1 = span[1];

          *worldlat = lat0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
            return status;
          }
          d0 = fabs(pixcrd[mixpix] - pixmix);

          double d  = dmin;

          *worldlat = lat1;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
            return status;
          }
          d1 = fabs(pixcrd[mixpix] - pixmix);

          for (int iter = 0; iter < niter; iter++) {
            double lat0m = (lat0 + lat)/2.0;
            *worldlat = lat0m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
              return status;
            }
            double d0m = fabs(pixcrd[mixpix] - pixmix);

            if (d0m < tol) return 0;

            double lat1m = (lat1 + lat)/2.0;
            *worldlat = lat1m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
              return status;
            }
            double d1m = fabs(pixcrd[mixpix] - pixmix);

            if (d1m < tol) return 0;

            if (d0m < d && d0m <= d1m) {
              lat1 = lat;
              d1   = d;
              lat  = lat0m;
              d    = d0m;
            } else if (d1m < d) {
              lat0 = lat;
              d0   = d;
              lat  = lat1m;
              d    = d1m;
            } else {
              lat0 = lat0m;
              d0   = d0m;
              lat1 = lat1m;
              d1   = d1m;
            }
          }
        }
      }

    } else {
      // Celestial latitude is given.

      // Check whether the solution interval is a crossing interval.
      double lng0 = span[0];
      *worldlng = lng0;
      int stat[1];
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
        return status;
      }
      double d0 = pixcrd[mixpix] - pixmix;

      double dabs = fabs(d0);
      if (dabs < tol) return 0;

      double lng1 = span[1];
      *worldlng = lng1;
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
        return status;
      }
      double d1 = pixcrd[mixpix] - pixmix;

      dabs = fabs(d1);
      if (dabs < tol) return 0;
      double lmin = lng1;
      double dmin = dabs;

      // Check for a crossing point.
      int crossed;
      double dx = 0.0;
      if (signbit(d0) != signbit(d1)) {
        crossed = 1;
        dx = d1;
      } else {
        crossed = 0;
        lng0 = span[1];
      }

      for (int retry = 0; retry < 4; retry++) {
        // Refine the solution interval.
        while (lng0 > span[0]) {
          lng0 -= step;
          if (lng0 < span[0]) lng0 = span[0];
          *worldlng = lng0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
            return status;
          }
          d0 = pixcrd[mixpix] - pixmix;

          // Check for a solution.
          dabs = fabs(d0);
          if (dabs < tol) return 0;

          // Record the point of closest approach.
          if (dabs < dmin) {
            lmin = lng0;
            dmin = dabs;
          }

          // Check for a crossing point.
          if (signbit(d0) != signbit(d1)) {
            crossed = 2;
            dx = d0;
            break;
          }

          // Advance to the next subinterval.
          lng1 = lng0;
          d1 = d0;
        }

        if (crossed) {
          // A crossing point was found.
          for (int iter = 0; iter < niter; iter++) {
            // Use regula falsi division of the interval.
            double lambda = d0/(d0-d1);
            if (lambda < 0.1) {
              lambda = 0.1;
            } else if (lambda > 0.9) {
              lambda = 0.9;
            }

            double dlng = lng1 - lng0;
            double lng = lng0 + lambda*dlng;
            *worldlng = lng;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
              return status;
            }

            // Check for a solution.
            double d = pixcrd[mixpix] - pixmix;
            dabs = fabs(d);
            if (dabs < tol) return 0;

            if (dlng < tol) {
              // An artifact of numerical imprecision.
              if (dabs < tol2) return 0;

              // Must be a discontinuity.
              break;
            }

            // Record the point of closest approach.
            if (dabs < dmin) {
              lmin = lng;
              dmin = dabs;
            }

            if (signbit(d0) == signbit(d)) {
              lng0 = lng;
              d0 = d;
            } else {
              lng1 = lng;
              d1 = d;
            }
          }

          // No convergence, must have been a discontinuity.
          if (crossed == 1) lng0 = span[1];
          lng1 = lng0;
          d1 = dx;
          crossed = 0;

        } else {
          // No crossing point; look for a tangent point.
          if (lmin == span[0]) break;
          if (lmin == span[1]) break;

          double lng = lmin;
          lng0 = lng - step;
          if (lng0 < span[0]) lng0 = span[0];
          lng1 = lng + step;
          if (lng1 > span[1]) lng1 = span[1];

          *worldlng = lng0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
            return status;
          }
          d0 = fabs(pixcrd[mixpix] - pixmix);

          double d  = dmin;

          *worldlng = lng1;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
            return status;
          }
          d1 = fabs(pixcrd[mixpix] - pixmix);

          for (int iter = 0; iter < niter; iter++) {
            double lng0m = (lng0 + lng)/2.0;
            *worldlng = lng0m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
              return status;
            }
            double d0m = fabs(pixcrd[mixpix] - pixmix);

            if (d0m < tol) return 0;

            double lng1m = (lng1 + lng)/2.0;
            *worldlng = lng1m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
              return status;
            }
            double d1m = fabs(pixcrd[mixpix] - pixmix);

            if (d1m < tol) return 0;

            if (d0m < d && d0m <= d1m) {
              lng1 = lng;
              d1   = d;
              lng  = lng0m;
              d    = d0m;
            } else if (d1m < d) {
              lng0 = lng;
              d0   = d;
              lng  = lng1m;
              d    = d1m;
            } else {
              lng0 = lng0m;
              d0   = d0m;
              lng1 = lng1m;
              d1   = d1m;
            }
          }
        }
      }
    }
  }


  // Set cel0 to the unity transformation.
  struct wcsprm wcs0 = *wcs;
  wcs0.cel.euler[0] = -90.0;
  wcs0.cel.euler[1] =   0.0;
  wcs0.cel.euler[2] =  90.0;
  wcs0.cel.euler[3] =   1.0;
  wcs0.cel.euler[4] =   0.0;

  // No convergence, check for aberrant behaviour at a native pole.
  *theta = -90.0;
  for (int j = 1; j <= 2; j++) {
    // Could the celestial coordinate element map to a native pole?
    *phi = 0.0;
    *theta = -*theta;
    struct celprm *wcscel = &(wcs->cel);
    double lng, lat;
    sphx2s(wcscel->euler, 1, 1, 1, 1, phi, theta, &lng, &lat);

    if (mixcel == 1) {
      if (fabs(fmod(*worldlng-lng, 360.0)) > tol) continue;
      if (lat < span[0]) continue;
      if (lat > span[1]) continue;
      *worldlat = lat;
    } else {
      if (fabs(*worldlat-lat) > tol) continue;
      if (lng < span[0]) lng += 360.0;
      if (lng > span[1]) lng -= 360.0;
      if (lng < span[0]) continue;
      if (lng > span[1]) continue;
      *worldlng = lng;
    }

    // Is there a solution for the given pixel coordinate element?
    lng = *worldlng;
    lat = *worldlat;

    // Feed native coordinates to wcss2p() with cel0 set to unity.
    *worldlng = -180.0;
    *worldlat = *theta;
    int stat[1];
    if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                         stat))) {
      wcserr_clear(err);
      wcs->err = wcs0.err;
      if (status == WCSERR_BAD_WORLD) {
        status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
      }
      return status;
    }
    double d0 = pixcrd[mixpix] - pixmix;

    // Check for a solution.
    if (fabs(d0) < tol) {
      // Recall saved world coordinates.
      *worldlng = lng;
      *worldlat = lat;
      return 0;
    }

    // Search for a crossing interval.
    double phi0 = -180.0, phi1;
    double d1;
    for (int k = -179; k <= 180; k++) {
      phi1 = (double)k;
      *worldlng = phi1;
      if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        wcserr_clear(err);
        wcs->err = wcs0.err;
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
        return status;
      }
      d1 = pixcrd[mixpix] - pixmix;

      // Check for a solution.
      double dabs = fabs(d1);
      if (dabs < tol) {
        // Recall saved world coordinates.
        *worldlng = lng;
        *worldlat = lat;
        return 0;
      }

      // Is it a crossing interval?
      if (signbit(d0) != signbit(d1)) break;

      phi0 = phi1;
      d0 = d1;
    }

    for (int iter = 1; iter <= niter; iter++) {
      // Use regula falsi division of the interval.
      double lambda = d0/(d0-d1);
      if (lambda < 0.1) {
        lambda = 0.1;
      } else if (lambda > 0.9) {
        lambda = 0.9;
      }

      double dphi = phi1 - phi0;
      *worldlng = phi0 + lambda*dphi;
      if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        wcserr_clear(err);
        wcs->err = wcs0.err;
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
        return status;
      }

      // Check for a solution.
      double d = pixcrd[mixpix] - pixmix;
      double dabs = fabs(d);
      if (dabs < tol || (dphi < tol && dabs < tol2)) {
        // Recall saved world coordinates.
        *worldlng = lng;
        *worldlat = lat;
        return 0;
      }

      if (signbit(d0) == signbit(d)) {
        phi0 = *worldlng;
        d0 = d;
      } else {
        phi1 = *worldlng;
        d1 = d;
      }
    }
  }


  // No solution.
  return wcserr_set(WCS_ERRMSG(WCSERR_NO_SOLUTION));
}

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

int wcsccs(
  struct wcsprm *wcs,
  double lng2P1,
  double lat2P1,
  double lng1P2,
  const char *clng,
  const char *clat,
  const char *radesys,
  double equinox,
  const char *alt)

{
  static const char *function = "wcsccs";

  int status;

  // Initialize if required.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  if (abs(wcs->flag) != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  if (wcs->lng < 0 || wcs->lat < 0) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_SUBIMAGE),
      "Image does not have celestial axes");
  }

  // (lng1XX,lat1XX)  ...longitude and latitude of XX in the old system.
  // (lng2XX,lat2XX)  ...longitude and latitude of XX in the new system.
  // XX = NP          ...natuve pole,
  //      P1          ...pole of the old system,
  //      P2          ...pole of the new system,
  //      FP          ...fiducial point.

  // Set up the transformation from the old to the new system.
  double euler12[5];
  euler12[0] = lng2P1;
  euler12[1] = 90.0 - lat2P1;
  euler12[2] = lng1P2;
  euler12[3] = cosd(euler12[1]);
  euler12[4] = sind(euler12[1]);

  // Transform coordinates of the fiducial point (FP) to the new system.
  double lng1FP = wcs->crval[wcs->lng];
  double lat1FP = wcs->crval[wcs->lat];
  double lng2FP, lat2FP;
  (void)sphx2s(euler12, 1, 1, 1, 1, &lng1FP, &lat1FP, &lng2FP, &lat2FP);

  // Compute native coordinates of the new pole (noting lat1P2 == lat2P1).
  double phiP2, thetaP2;
  (void)sphs2x(wcs->cel.euler, 1, 1, 1, 1, &lng1P2, &lat2P1,
               &phiP2, &thetaP2);

  if (fabs(lat2FP) == 90.0 || fabs(thetaP2) == 90.0) {
    // If one of the poles of the new system is at the fiducial point, then
    // lng2FP is indeterminate, and if one of them is at the native pole, then
    // phiP2 is indeterminate.  We have to work harder to obtain these values.

    // Compute coordinates of the native pole (NP) in the old and new systems.
    double phiNP = 0.0, thetaNP = 90.0;
    double lng1NP, lat1NP;
    (void)sphx2s(wcs->cel.euler, 1, 1, 1, 1, &phiNP, &thetaNP,
                 &lng1NP, &lat1NP);

    double lng2NP, lat2NP;
    (void)sphx2s(euler12, 1, 1, 1, 1, &lng1NP, &lat1NP, &lng2NP, &lat2NP);

    // Native latitude and longitude of the fiducial point, (phi0,theta0).
    double phiFP   = wcs->cel.prj.phi0;
    double thetaFP = wcs->cel.prj.theta0;

    if (fabs(lat2NP) == 90.0) {
      // Following WCS Paper II equations (3) and (4), we are free to choose
      // phiP2 and set lng2NP accordingly.  So set phiP2 to its default value
      // for the projection.
      if (thetaFP < lat2FP) {
        phiP2 = 0.0;
      } else {
        phiP2 = 180.0;
      }

      // Compute coordinates in the old system of test point X.
      double phiX = 0.0, thetaX = 0.0;
      double lng1X, lat1X;
      (void)sphx2s(wcs->cel.euler, 1, 1, 1, 1, &phiX, &thetaX,
                   &lng1X, &lat1X);

      // Ensure that lng1X is not indeterminate.
      if (fabs(lat1X) == 90.0) {
        phiX = 90.0;
        (void)sphx2s(wcs->cel.euler, 1, 1, 1, 1, &phiX, &thetaX,
                     &lng1X, &lat1X);
      }

      // Compute coordinates in the new system of test point X.
      double lng2X, lat2X;
      (void)sphx2s(euler12, 1, 1, 1, 1, &lng1X, &lat1X, &lng2X, &lat2X);

      // Apply WCS Paper II equations (3) and (4).
      if (lat2NP == +90.0) {
        lng2NP = lng2X + (phiP2 - phiX) + 180.0;
      } else {
        lng2NP = lng2X - (phiP2 - phiX);
      }

    } else {
      // For (lng2NP + 90, 0), WCS Paper II equation (5) reduces to
      // phi = phiP2 - 90.
      double lng2X = lng2NP + 90.0;
      double lat2X = 0.0;
      double lng1X, lat1X;
      (void)sphs2x(euler12, 1, 1, 1, 1, &lng2X, &lat2X, &lng1X, &lat1X);

      double phiX, thetaX;
      (void)sphs2x(wcs->cel.euler, 1, 1, 1, 1, &lng1X, &lat1X,
                   &phiX, &thetaX);

      phiP2 = phiX + 90.0;
    }

    // Compute the longitude of the fiducial point in the new system.
    double eulerN2[5];
    eulerN2[0] = lng2NP;
    eulerN2[1] = 90.0 - lat2NP;
    eulerN2[2] = phiP2;
    eulerN2[3] = cosd(eulerN2[1]);
    eulerN2[4] = sind(eulerN2[1]);

    (void)sphx2s(eulerN2, 1, 1, 1, 1, &phiFP, &thetaFP, &lng2FP, &lat2FP);
  }

  // Update reference values in wcsprm.
  wcs->crval[wcs->lng] = lng2FP;
  wcs->crval[wcs->lat] = lat2FP;
  wcs->lonpole = phiP2;
  wcs->latpole = thetaP2;

  // Update wcsprm::ctype.
  if (clng) {
    strncpy(wcs->ctype[wcs->lng], clng, 4);
    for (int i = 0; i < 4; i++) {
      if (wcs->ctype[wcs->lng][i] == '\0') {
        wcs->ctype[wcs->lng][i] = '-';
      }
    }
  }

  if (clat) {
    strncpy(wcs->ctype[wcs->lat], clat, 4);
    for (int i = 0; i < 4; i++) {
      if (wcs->ctype[wcs->lat][i] == '\0') {
        wcs->ctype[wcs->lat][i] = '-';
      }
    }
  }

  // Update auxiliary values.
  if (strncmp(wcs->ctype[wcs->lng], "RA--", 4) == 0 &&
      strncmp(wcs->ctype[wcs->lat], "DEC-", 4) == 0) {
    // Transforming to equatorial coordinates.
    if (radesys) {
      strncpy(wcs->radesys, radesys, 71);
    }

    if (equinox != 0.0) {
      wcs->equinox = equinox;
    }
  } else {
    // Meaningless for other than equatorial coordinates.
    memset(wcs->radesys, 0, 72);
    wcs->equinox = UNDEFINED;
  }

  if (alt && *alt) {
    wcs->alt[0] = *alt;
  }

  // Reset the struct.
  wcs->flag = (wcs->flag == -WCSSET) ? 1 : 0;
  if ((status = wcsset(wcs))) return status;

  return 0;
}

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

int wcssptr(
  struct wcsprm *wcs,
  int  *i,
  char ctype[9])

{
  static const char *function = "wcssptr";

  int status;

  // Initialize if required.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  if (abs(wcs->flag) != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  int j;
  if ((j = *i) < 0) {
    if ((j = wcs->spec) < 0) {
      // Look for a linear spectral axis.
      for (j = 0; j < wcs->naxis; j++) {
        if (wcs->types[j]/100 == 30) {
          break;
        }
      }

      if (j >= wcs->naxis) {
        // No spectral axis.
        return wcserr_set(WCSERR_SET(WCSERR_BAD_SUBIMAGE),
          "No spectral axis found");
      }
    }

    *i = j;
  }

  // Translate the spectral axis.
  double cdelt, crval;
  if ((status = spctrne(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                        wcs->restfrq, wcs->restwav, ctype, &crval, &cdelt,
                        &(wcs->spc.err)))) {
    return wcserr_set(WCS_ERRMSG(wcs_spcerr[status]));
  }


  // Translate keyvalues.
  wcs->cdelt[j] = cdelt;
  wcs->crval[j] = crval;
  spctyp(ctype, 0x0, 0x0, 0x0, wcs->cunit[j], 0x0, 0x0, 0x0);
  strncpy(wcs->ctype[j], ctype, 72);

  // This keeps things tidy if the spectral axis is linear.
  spcfree(&(wcs->spc));
  spcini(&(wcs->spc));

  // Reset the struct.
  wcs->flag = (wcs->flag == -WCSSET) ? 1 : 0;
  if ((status = wcsset(wcs))) return status;

  return 0;
}

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

#define STRINGIZE(s) STRINGIFY(s)
#define STRINGIFY(s) #s

const char *wcslib_version(
  int  vers[3])

{
  static const char *wcsver = STRINGIZE(WCSLIB_VERSION);

  if (vers != 0x0) {
    vers[2] = 0;
    sscanf(wcsver, "%d.%d.%d", vers, vers+1, vers+2);
  }

  return wcsver;
}
@


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: wcs.c,v 8.5.1.2 2026/03/29 13:36:16 mcalabre Exp mcalabre $
d28 1
d34 1
d50 1
a50 1
// Maximum number of PVi_ma and PSi_ma keywords.
d54 3
d226 1
d228 1
a228 1
    return wcserr_set(WCSERR_SET(WCSERR_MEMORY),
d232 8
d275 1
a275 1
        if ((wcs->crpix = calloc(naxis, sizeof(double))) == 0x0) {
d291 1
a291 1
        if ((wcs->pc = calloc(naxis*naxis, sizeof(double))) == 0x0) {
d308 1
a308 1
        if ((wcs->cdelt = calloc(naxis, sizeof(double))) == 0x0) {
d325 1
a325 1
        if ((wcs->crval = calloc(naxis, sizeof(double))) == 0x0) {
d342 1
a342 1
        if ((wcs->cunit = calloc(naxis, sizeof(char [72]))) == 0x0) {
d359 1
a359 1
        if ((wcs->ctype = calloc(naxis, sizeof(char [72]))) == 0x0) {
d422 1
a422 1
        if ((wcs->cd = calloc(naxis*naxis, sizeof(double))) == 0x0) {
d439 1
a439 1
        if ((wcs->crota = calloc(naxis, sizeof(double))) == 0x0) {
d456 1
a456 1
        if ((wcs->colax = calloc(naxis, sizeof(int))) == 0x0) {
d473 1
a473 1
        if ((wcs->cname = calloc(naxis, sizeof(char [72]))) == 0x0) {
d490 1
a490 1
        if ((wcs->crder = calloc(naxis, sizeof(double))) == 0x0) {
d507 1
a507 1
        if ((wcs->csyer = calloc(naxis, sizeof(double))) == 0x0) {
d524 1
a524 1
        if ((wcs->czphs = calloc(naxis, sizeof(double))) == 0x0) {
d541 1
a541 1
        if ((wcs->cperi = calloc(naxis, sizeof(double))) == 0x0) {
d687 2
a688 2
  strcpy(wcs->lngtyp, "    ");
  strcpy(wcs->lattyp, "    ");
d995 2
a996 2
        int axmap[32];
        for (int jhat = 0; jhat < 32; jhat++) {
d1012 1
a1012 1
          if (strncmp(fp, "NAXES", 6) == 0) {
d1021 1
a1021 1
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat || 32 < Nhat) {
d1083 2
a1084 1
        return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d1398 2
a1399 2
        int axmap[32];
        for (int jhat = 0; jhat < 32; jhat++) {
d1412 1
a1412 1
          if (strncmp(fp, "NAXES", 6) == 0) {
d1443 1
a1443 1
          sprintf(ctmp, "%d", j+1);
d1450 1
a1450 1
          if (strncmp(fp, "NAXES", 6) == 0) {
d1452 1
a1452 1
              strcpy(dpdst->field, dpsrc->field);
d1455 2
a1456 1
              sprintf(fp, "AXIS.%d", jhat+1);
d1570 1
a1570 1
        if (strncmp(wcs1->ps[i].value, wcs2->ps[j].value, 72)) {
d1592 1
a1592 1
    if (strncmp(wcs1->alt, wcs2->alt, 4) ||
d1600 7
a1606 7
        strncmp(wcs1->wcsname,  wcs2->wcsname,  72) ||
        strncmp(wcs1->timesys,  wcs2->timesys,  72) ||
        strncmp(wcs1->trefpos,  wcs2->trefpos,  72) ||
        strncmp(wcs1->trefdir,  wcs2->trefdir,  72) ||
        strncmp(wcs1->plephem,  wcs2->plephem,  72) ||
        strncmp(wcs1->timeunit, wcs2->timeunit, 72) ||
        strncmp(wcs1->dateref,  wcs2->dateref,  72) ||
d1609 4
a1612 4
        strncmp(wcs1->dateobs,  wcs2->dateobs, 72) ||
        strncmp(wcs1->datebeg,  wcs2->datebeg, 72) ||
        strncmp(wcs1->dateavg,  wcs2->dateavg, 72) ||
        strncmp(wcs1->dateend,  wcs2->dateend, 72) ||
d1628 2
a1629 2
        strncmp(wcs1->obsorbit, wcs2->obsorbit, 72) ||
        strncmp(wcs1->radesys,  wcs2->radesys,  72) ||
d1631 2
a1632 2
        strncmp(wcs1->specsys,  wcs2->specsys,  72) ||
        strncmp(wcs1->ssysobs,  wcs2->ssysobs,  72) ||
d1635 1
a1635 1
        strncmp(wcs1->ssyssrc,  wcs2->ssyssrc,  72) ||
d1820 3
a1822 1
        if ((wcs->pv = wcs->m_pv = realloc(wcs->m_pv, size))) {
d1837 3
a1839 1
        if ((wcs->ps = wcs->m_ps = realloc(wcs->m_ps, size))) {
d1930 1
a1930 1
  sizes[1] += naxis * sizeof(double);
d1933 1
a1933 1
  sizes[1] += naxis*naxis * sizeof(double);
d1936 1
a1936 1
  sizes[1] += naxis * sizeof(double);
d1939 1
a1939 1
  sizes[1] += naxis * sizeof(double);
d1943 1
a1943 1
    sizes[1] += naxis * sizeof(char [72]);
d1947 1
a1947 1
  sizes[1] += naxis * sizeof(char [72]);
d1951 1
a1951 1
    sizes[1] += wcs->npvmax * sizeof(struct pvcard);
d1956 1
a1956 1
    sizes[1] += wcs->npsmax * sizeof(struct pscard);
d1961 1
a1961 1
    sizes[1] += naxis*naxis * sizeof(double);
d1966 1
a1966 1
    sizes[1] += naxis * sizeof(double);
d1971 1
a1971 1
    sizes[1] += naxis * sizeof(int);
d1976 1
a1976 1
    sizes[1] += naxis * sizeof(char [72]);
d1981 1
a1981 1
    sizes[1] += naxis * sizeof(double);
d1986 1
a1986 1
    sizes[1] += naxis * sizeof(double);
d1991 1
a1991 1
    sizes[1] += naxis * sizeof(double);
d1996 1
a1996 1
    sizes[1] += naxis * sizeof(double);
d2001 1
a2001 1
    sizes[1] += sizeof(struct auxprm);
d2012 1
a2012 1
    sizes[1] += wcs->nwtb * sizeof(struct wtbarr);
d2037 1
a2037 1
  sizes[0] = sizeof(struct auxprm);
d2485 6
a2490 2
      WCSPRINTF_PTR("     arrayp: ", wtbp->arrayp, " -> ");
      WCSPRINTF_PTR("", *(wtbp->arrayp), "\n");
d2581 1
a2581 1
  if (32 < naxis) {
d2583 1
a2583 1
      "naxis must not exceed 32 (got %d)", naxis);
d2619 1
a2619 1
        strcpy(dpq, "DP");
d2623 1
a2623 1
        strcpy(dpq, "DQ");
d2627 2
a2628 2
      strcpy(dis->dtype[wcs->lng], "TPV");
      strcpy(dis->dtype[wcs->lat], "TPV");
d2634 1
a2634 1
      sprintf(dpq+2, "%d", wcs->lng+1);
d2643 1
a2643 1
        sprintf(keyp->field, "%s.TPV.%d", dpq, wcs->pv[k].m);
d2649 1
a2649 1
      sprintf(dpq+2, "%d", wcs->lat+1);
d2657 1
a2657 1
        sprintf(keyp->field, "%s.TPV.%d", dpq, wcs->pv[k].m);
d2676 1
a2676 1
      strcpy(wcsprj->code, "TAN");
d2680 2
a2681 2
      strcpy(wcs->ctype[wcs->lng]+5, "TAN");
      strcpy(wcs->ctype[wcs->lat]+5, "TAN");
d2685 3
a2687 3
      strcpy(wcsprj->code, "TAN");
      strcpy(wcs->ctype[wcs->lng]+5, "TAN");
      strcpy(wcs->ctype[wcs->lat]+5, "TAN");
d2691 3
a2693 3
      strcpy(wcsprj->code, "ZPN");
      strcpy(wcs->ctype[wcs->lng]+5, "ZPN");
      strcpy(wcs->ctype[wcs->lat]+5, "ZPN");
d2746 1
a2746 1
      strcpy(wcsprj->code, "SFL");
d2755 1
a2755 1
      strcpy(wcsprj->code, "SIN");
d2789 3
d2807 2
a2808 2
    strcpy(wcsspc->type, stype);
    strcpy(wcsspc->code, scode);
d2872 1
a2872 1
      int i, j;
d2905 1
a2905 1
        strcpy(wcs->radesys, "ICRS");
d2907 1
a2907 1
        strcpy(wcs->radesys, "FK4");
d2909 1
a2909 1
        strcpy(wcs->radesys, "FK5");
d3056 2
a3057 2
      strcpy(wcs->ctype[i], ctypei);
      if (wcs->specsys[0] == '\0') strcpy(wcs->specsys, specsys);
d3074 1
a3074 1
          strcpy(wcs->lngtyp, ctypei);
d3084 1
a3084 1
          strcpy(wcs->lattyp, ctypei);
d3158 1
a3158 1
      sprintf(pcode, "%.3s", ctypei+5);
d3162 2
a3163 2
        strcpy(wcs->lngtyp, "RA");
        strcpy(wcs->lattyp, "DEC");
d3165 1
a3165 1
        sprintf(requir, "DEC--%s", pcode);
d3168 2
a3169 2
        strcpy(wcs->lngtyp, "RA");
        strcpy(wcs->lattyp, "DEC");
d3171 1
a3171 1
        sprintf(requir, "RA---%s", pcode);
d3174 2
a3175 2
        sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
        sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
d3177 1
a3177 1
        sprintf(requir, "%s-%s", wcs->lattyp, pcode);
d3180 2
a3181 2
        sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
        sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
d3183 1
a3183 1
        sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
d3186 2
a3187 2
        sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
        sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
d3189 1
a3189 1
        sprintf(requir, "%s-%s", wcs->lattyp, pcode);
d3192 2
a3193 2
        sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
        sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
d3195 1
a3195 1
        sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
d3228 1
a3228 1
  if (strcmp(requir, "")) {
d3296 2
a3297 2
    if (strncmp(code, "-LOG", 5) == 0) return 1;
    if (strncmp(code, "-TAB", 5) == 0) return 1;
d3323 1
a3323 1
      strcpy(units, "deg");
d3328 1
a3328 1
      strncpy(ctype, wcs->ctype[i], 8);
d3362 2
a3363 1
            *(wcs->cd + i*naxis + j) *= scale;
d3367 1
a3367 1
        strcpy(wcs->cunit[i], units);
d3371 1
a3371 1
      strcpy(wcs->cunit[i], units);
d3429 7
a3435 5
  chksum = wcs_fletcher32(chksum, &wcs->altlin, szi);
  chksum = wcs_fletcher32(chksum, &wcs->ntab, szi);
  chksum = wcs_fletcher32(chksum, &wcs->nwtb, szi);
  chksum = wcs_fletcher32(chksum, &wcs->tab, sizeof(struct tabprm *));
  chksum = wcs_fletcher32(chksum, &wcs->wtb, sizeof(struct wtbarr *));
d3551 2
a3552 3
            if (dispre && dispre->disp2x[i]) {
              disaxes |= (1 << i);
            } else if (disseq && disseq->disp2x[i]) {
d3634 1
d4006 2
a4007 3
            if (dispre && dispre->disp2x[i]) {
              disaxes |= (1 << i);
            } else if (disseq && disseq->disp2x[i]) {
d4924 1
a4924 1
  strcpy(wcs->ctype[j], ctype);
@


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


8.6.1.2
log
@Include wcslimits.h to get NAXMAX and set the values of the global variables
it declares.  In wcsinit(), return WCSERR_BAD_PARAM rather than WCSERR_MEMORY
if naxis is negative.  In wcsset() and wcssub(), use NAXMAX instead of a
hard-coded value (32).
Inconsequential change prompted by clang-tidy:
 - In wcsinit(), check that naxis does not exceed NAXMAX
   (bugprone-implicit-widening-of-multiplication-result).
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.6.1.1 2026/03/29 14:19:26 mcalabre Exp mcalabre $
a32 1
#include "wcslimits.h"
d48 1
a48 4
// Maximum number of image axes, NAXIS.
const int NAXMAX = 32;

// Maximum number of PVi_ma and PSi_ma keywords.  May be changed by wcsnpv().
a51 3
// Maximum number of DPja or DQia keywords.  May be changed by disndp().
int NDPMAX = 256;

a220 1
  // Sanity check on naxis.
d222 1
a222 1
    return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
a225 5
  if (NAXMAX < naxis) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
      "naxis exceeds %d (got %d)", NAXMAX, naxis);
  }

d981 2
a982 2
        int axmap[NAXMAX];
        for (int jhat = 0; jhat < NAXMAX; jhat++) {
d1007 1
a1007 1
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat) {
d1383 2
a1384 2
        int axmap[NAXMAX];
        for (int jhat = 0; jhat < NAXMAX; jhat++) {
d2557 1
a2557 1
  if (NAXMAX < naxis) {
d2559 1
a2559 1
      "naxis must not exceed %d (got %d)", NAXMAX, naxis);
@


8.6.1.3
log
@Inconsequential changes prompted by clang-tidy:
 - Replaced use of strcpy() with strncpy(), and sprintf() with snprintf()
   (clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling).
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.6.1.2 2026/04/05 08:43:34 mcalabre Exp mcalabre $
d686 2
a687 2
  strncpy(wcs->lngtyp, "    ", 8);
  strncpy(wcs->lattyp, "    ", 8);
d1441 1
a1441 1
          snprintf(ctmp, 16, "%d", j+1);
d1450 1
a1450 1
              strncpy(dpdst->field, dpsrc->field, 72);
d1453 1
a1453 2
              size_t fsize = (dpdst->field + 72) - fp;
              snprintf(fp, fsize, "AXIS.%d", jhat+1);
d2608 1
a2608 1
        strncpy(dpq, "DP", 16);
d2612 1
a2612 1
        strncpy(dpq, "DQ", 16);
d2616 2
a2617 2
      strncpy(dis->dtype[wcs->lng], "TPV", 72);
      strncpy(dis->dtype[wcs->lat], "TPV", 72);
d2623 1
a2623 1
      snprintf(dpq+2, 14, "%d", wcs->lng+1);
d2632 1
a2632 1
        snprintf(keyp->field, 72, "%s.TPV.%d", dpq, wcs->pv[k].m);
d2638 1
a2638 1
      snprintf(dpq+2, 14, "%d", wcs->lat+1);
d2646 1
a2646 1
        snprintf(keyp->field, 72, "%s.TPV.%d", dpq, wcs->pv[k].m);
d2665 1
a2665 1
      strncpy(wcsprj->code, "TAN", 4);
d2669 2
a2670 2
      strncpy(wcs->ctype[wcs->lng]+5, "TAN", 4);
      strncpy(wcs->ctype[wcs->lat]+5, "TAN", 4);
d2674 3
a2676 3
      strncpy(wcsprj->code, "TAN", 4);
      strncpy(wcs->ctype[wcs->lng]+5, "TAN", 4);
      strncpy(wcs->ctype[wcs->lat]+5, "TAN", 4);
d2680 3
a2682 3
      strncpy(wcsprj->code, "ZPN", 4);
      strncpy(wcs->ctype[wcs->lng]+5, "ZPN", 4);
      strncpy(wcs->ctype[wcs->lat]+5, "ZPN", 4);
d2735 1
a2735 1
      strncpy(wcsprj->code, "SFL", 4);
d2744 1
a2744 1
      strncpy(wcsprj->code, "SIN", 4);
d2793 2
a2794 2
    strncpy(wcsspc->type, stype, 8);
    strncpy(wcsspc->code, scode, 4);
d2891 1
a2891 1
        strncpy(wcs->radesys, "ICRS", 72);
d2893 1
a2893 1
        strncpy(wcs->radesys, "FK4", 72);
d2895 1
a2895 1
        strncpy(wcs->radesys, "FK5", 72);
d3042 2
a3043 2
      strncpy(wcs->ctype[i], ctypei, 72);
      if (wcs->specsys[0] == '\0') strncpy(wcs->specsys, specsys, 72);
d3060 1
a3060 1
          strncpy(wcs->lngtyp, ctypei, 8);
d3070 1
a3070 1
          strncpy(wcs->lattyp, ctypei, 8);
d3144 1
a3144 1
      snprintf(pcode, 4, "%.3s", ctypei+5);
d3148 2
a3149 2
        strncpy(wcs->lngtyp, "RA", 8);
        strncpy(wcs->lattyp, "DEC", 8);
d3151 1
a3151 1
        snprintf(requir, 16, "DEC--%s", pcode);
d3154 2
a3155 2
        strncpy(wcs->lngtyp, "RA", 8);
        strncpy(wcs->lattyp, "DEC", 8);
d3157 1
a3157 1
        snprintf(requir, 16, "RA---%s", pcode);
d3160 2
a3161 2
        snprintf(wcs->lngtyp, 8, "%cLON", ctypei[0]);
        snprintf(wcs->lattyp, 8, "%cLAT", ctypei[0]);
d3163 1
a3163 1
        snprintf(requir, 16, "%s-%s", wcs->lattyp, pcode);
d3166 2
a3167 2
        snprintf(wcs->lngtyp, 8, "%cLON", ctypei[0]);
        snprintf(wcs->lattyp, 8, "%cLAT", ctypei[0]);
d3169 1
a3169 1
        snprintf(requir, 16, "%s-%s", wcs->lngtyp, pcode);
d3172 2
a3173 2
        snprintf(wcs->lngtyp, 8, "%c%cLN", ctypei[0], ctypei[1]);
        snprintf(wcs->lattyp, 8, "%c%cLT", ctypei[0], ctypei[1]);
d3175 1
a3175 1
        snprintf(requir, 16, "%s-%s", wcs->lattyp, pcode);
d3178 2
a3179 2
        snprintf(wcs->lngtyp, 8, "%c%cLN", ctypei[0], ctypei[1]);
        snprintf(wcs->lattyp, 8, "%c%cLT", ctypei[0], ctypei[1]);
d3181 1
a3181 1
        snprintf(requir, 16, "%s-%s", wcs->lngtyp, pcode);
d3309 1
a3309 1
      strncpy(units, "deg", 16);
d3314 1
a3314 1
      strncpy(ctype, wcs->ctype[i], 9);
d3352 1
a3352 1
        strncpy(wcs->cunit[i], units, 72);
d3356 1
a3356 1
      strncpy(wcs->cunit[i], units, 72);
d4908 1
a4908 1
  strncpy(wcs->ctype[j], ctype, 72);
@


8.6.1.4
log
@Found by clang-tidy:
 - In wcstrim(), need to ensure that realloc() succeeds before assigning its
   return value otherwise a memory leak would occur when the pointer is
   overwritten with NULL (bugprone-suspicious-realloc-usage).
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.6.1.3 2026/04/10 06:38:13 mcalabre Exp mcalabre $
d1818 1
a1818 3
        struct pvcard *pvp = realloc(wcs->m_pv, size);
        if (pvp != 0x0) {
          wcs->pv = wcs->m_pv = pvp;
d1833 1
a1833 3
        struct pscard *psp = realloc(wcs->m_ps, size);
        if (psp != 0x0) {
          wcs->ps = wcs->m_ps = psp;
@


8.6.1.5
log
@Found by clang-tidy:
 - Prevent possible dereference of NULL pointer in wcsprt()
   (clang-analyzer-core.NullDereference).
 - Prevent possible memory leak if memory allocation fails in wcssub()
   (clang-analyzer-unix.Malloc).
Further inconsequential changes prompted by clang-tidy:
 - Restructured if-blocks in wcss2p() and wcsp2s() to avoid duplication
   (bugprone-branch-clone).
 - Use size_t for memory address and size calculations and allocation
   (bugprone-implicit-widening-of-multiplication-result).
 - In wcs_chksum(), explicitly cast pointers used as function arguments
   (bugprone-multi-level-implicit-pointer-conversion).
 - Explicitly cast return value of sizeof() to int when doing memory
   calculations (bugprone-narrowing-conversions).
 - Use strcmp() rather then strncmp() for comparison with a string constant
   (bugprone-not-null-terminated-result).
 - Explicitly test the return value of strncmp() in if-statements
   (bugprone-suspicious-string-compare).
 - Added (empty) default case to a switch statement in wcsset()
   (bugprone-switch-missing-default-case).
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.6.1.4 2026/04/12 11:41:38 mcalabre Exp mcalabre $
a27 1
#include <stddef.h>
a238 3
  // Balm for clang-tidy.
  size_t naxszt = naxis;

d274 1
a274 1
        if ((wcs->crpix = calloc(naxszt, sizeof(double))) == 0x0) {
d290 1
a290 1
        if ((wcs->pc = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
d307 1
a307 1
        if ((wcs->cdelt = calloc(naxszt, sizeof(double))) == 0x0) {
d324 1
a324 1
        if ((wcs->crval = calloc(naxszt, sizeof(double))) == 0x0) {
d341 1
a341 1
        if ((wcs->cunit = calloc(naxszt, sizeof(char [72]))) == 0x0) {
d358 1
a358 1
        if ((wcs->ctype = calloc(naxszt, sizeof(char [72]))) == 0x0) {
d421 1
a421 1
        if ((wcs->cd = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
d438 1
a438 1
        if ((wcs->crota = calloc(naxszt, sizeof(double))) == 0x0) {
d455 1
a455 1
        if ((wcs->colax = calloc(naxszt, sizeof(int))) == 0x0) {
d472 1
a472 1
        if ((wcs->cname = calloc(naxszt, sizeof(char [72]))) == 0x0) {
d489 1
a489 1
        if ((wcs->crder = calloc(naxszt, sizeof(double))) == 0x0) {
d506 1
a506 1
        if ((wcs->csyer = calloc(naxszt, sizeof(double))) == 0x0) {
d523 1
a523 1
        if ((wcs->czphs = calloc(naxszt, sizeof(double))) == 0x0) {
d540 1
a540 1
        if ((wcs->cperi = calloc(naxszt, sizeof(double))) == 0x0) {
d1011 1
a1011 1
          if (strcmp(fp, "NAXES") == 0) {
d1082 1
a1082 2
        status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        goto cleanup;
d1410 1
a1410 1
          if (strcmp(fp, "NAXES") == 0) {
d1448 1
a1448 1
          if (strcmp(fp, "NAXES") == 0) {
d1568 1
a1568 1
        if (strncmp(wcs1->ps[i].value, wcs2->ps[j].value, 72) != 0) {
d1590 1
a1590 1
    if (strncmp(wcs1->alt, wcs2->alt, 4) != 0 ||
d1598 7
a1604 7
        strncmp(wcs1->wcsname,  wcs2->wcsname,  72) != 0 ||
        strncmp(wcs1->timesys,  wcs2->timesys,  72) != 0 ||
        strncmp(wcs1->trefpos,  wcs2->trefpos,  72) != 0 ||
        strncmp(wcs1->trefdir,  wcs2->trefdir,  72) != 0 ||
        strncmp(wcs1->plephem,  wcs2->plephem,  72) != 0 ||
        strncmp(wcs1->timeunit, wcs2->timeunit, 72) != 0 ||
        strncmp(wcs1->dateref,  wcs2->dateref,  72) != 0 ||
d1607 4
a1610 4
        strncmp(wcs1->dateobs,  wcs2->dateobs, 72) != 0 ||
        strncmp(wcs1->datebeg,  wcs2->datebeg, 72) != 0 ||
        strncmp(wcs1->dateavg,  wcs2->dateavg, 72) != 0 ||
        strncmp(wcs1->dateend,  wcs2->dateend, 72) != 0 ||
d1626 2
a1627 2
        strncmp(wcs1->obsorbit, wcs2->obsorbit, 72) != 0 ||
        strncmp(wcs1->radesys,  wcs2->radesys,  72) != 0 ||
d1629 2
a1630 2
        strncmp(wcs1->specsys,  wcs2->specsys,  72) != 0 ||
        strncmp(wcs1->ssysobs,  wcs2->ssysobs,  72) != 0 ||
d1633 1
a1633 1
        strncmp(wcs1->ssyssrc,  wcs2->ssyssrc,  72) != 0 ||
d1928 1
a1928 1
  sizes[1] += naxis * (int)sizeof(double);
d1931 1
a1931 1
  sizes[1] += naxis*naxis * (int)sizeof(double);
d1934 1
a1934 1
  sizes[1] += naxis * (int)sizeof(double);
d1937 1
a1937 1
  sizes[1] += naxis * (int)sizeof(double);
d1941 1
a1941 1
    sizes[1] += naxis * (int)sizeof(char [72]);
d1945 1
a1945 1
  sizes[1] += naxis * (int)sizeof(char [72]);
d1949 1
a1949 1
    sizes[1] += wcs->npvmax * (int)sizeof(struct pvcard);
d1954 1
a1954 1
    sizes[1] += wcs->npsmax * (int)sizeof(struct pscard);
d1959 1
a1959 1
    sizes[1] += naxis*naxis * (int)sizeof(double);
d1964 1
a1964 1
    sizes[1] += naxis * (int)sizeof(double);
d1969 1
a1969 1
    sizes[1] += naxis * (int)sizeof(int);
d1974 1
a1974 1
    sizes[1] += naxis * (int)sizeof(char [72]);
d1979 1
a1979 1
    sizes[1] += naxis * (int)sizeof(double);
d1984 1
a1984 1
    sizes[1] += naxis * (int)sizeof(double);
d1989 1
a1989 1
    sizes[1] += naxis * (int)sizeof(double);
d1994 1
a1994 1
    sizes[1] += naxis * (int)sizeof(double);
d1999 1
a1999 1
    sizes[1] += (int)sizeof(struct auxprm);
d2010 1
a2010 1
    sizes[1] += wcs->nwtb * (int)sizeof(struct wtbarr);
d2035 1
a2035 1
  sizes[0] = (int)sizeof(struct auxprm);
d2483 2
a2484 6
      WCSPRINTF_PTR("     arrayp: ", wtbp->arrayp, "");
      if (wtbp->arrayp) {
        WCSPRINTF_PTR(" -> ", *(wtbp->arrayp), "\n");
      } else {
        wcsprintf("\n");
      }
a2782 2
        default:
          // Ignore it.
d2863 1
a2863 1
      ptrdiff_t i, j;
d3219 1
a3219 1
  if (strcmp(requir, "") != 0) {
d3287 2
a3288 2
    if (strcmp(code, "-LOG") == 0) return 1;
    if (strcmp(code, "-TAB") == 0) return 1;
d3353 1
a3353 2
            ptrdiff_t cdij = i*naxis + j;
            *(wcs->cd + cdij) *= scale;
d3419 5
a3423 7
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->altlin), szi);
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->ntab), szi);
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->nwtb), szi);
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->tab),
                          sizeof(struct tabprm *));
  chksum = wcs_fletcher32(chksum, (const void *)(&wcs->wtb),
                          sizeof(struct wtbarr *));
d3539 3
a3541 2
            if (dispre && dispre->disp2x[i] ||
                disseq && disseq->disp2x[i]) {
d3994 3
a3996 2
            if (dispre && dispre->disp2x[i] ||
                disseq && disseq->disp2x[i]) {
@


8.6.1.6
log
@NAXMAX is now set in wcslimits.h as a preprocessor definition.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.6.1.5 2026/04/21 08:36:22 mcalabre Exp mcalabre $
d49 3
@


8.6.1.7
log
@Appeased pedantic compiler warnings.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.6.1.6 2026/04/22 15:11:39 mcalabre Exp mcalabre $
a2790 1
          break;
d3550 2
a3551 2
            if ((dispre && dispre->disp2x[i]) ||
                (disseq && disseq->disp2x[i])) {
a3632 1
              break;
d4004 2
a4005 2
            if ((dispre && dispre->disp2x[i]) ||
                (disseq && disseq->disp2x[i])) {
@


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: wcs.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: wcs.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: wcs.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: wcs.c,v 8.3.1.3 2024/07/09 09:12:30 mcalabre Exp mcalabre $
@


8.4.1.1
log
@WCSLIB 8.4 development branch.
@
text
@d22 1
a22 1
  $Id: wcs.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: wcs.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: wcs.c,v 8.2.1.11 2024/05/13 16:07:43 mcalabre Exp mcalabre $
a1768 2
  wcserr_clear(&(wcs->err));

d1773 2
d2376 5
a2386 5
  // Contained structs.
  wcsprintf("        lin: (see below)\n");
  wcsprintf("        cel: (see below)\n");
  wcsprintf("        spc: (see below)\n");

d3382 2
a3383 2
    size_t nszpv = wcs->npvmax * sizeof(struct pvcard);
    chksum = wcs_fletcher32(chksum, &wcs->pv, nszpv);
d3389 2
a3390 2
    size_t nszps = wcs->npsmax * sizeof(struct pscard);
    chksum = wcs_fletcher32(chksum, &wcs->ps, nszps);
d3394 1
a3394 1
    chksum = wcs_fletcher32(chksum, wcs->pc, nnszd);
d3423 1
a3423 1
//                      less than 259200 (no checks are made).
d3442 2
a3443 2
  c0 &= 65535;
  c1 &= 65535;
@


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


8.3.1.2
log
@Fixed some problems in wcs_chksum() and changed wcs_fletcher32() to
conform to the standard computation.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.3.1.1 2024/05/13 16:35:39 mcalabre Exp mcalabre $
d3382 2
a3383 2
    size_t nszpv = wcs->npv * sizeof(struct pvcard);
    chksum = wcs_fletcher32(chksum, wcs->pv, nszpv);
d3389 2
a3390 2
    size_t nszps = wcs->nps * sizeof(struct pscard);
    chksum = wcs_fletcher32(chksum, wcs->ps, nszps);
d3394 1
a3394 1
    chksum = wcs_fletcher32(chksum, wcs->cd, nnszd);
d3423 1
a3423 1
//                      between 0 and 259200 inclusive (no checks are made).
d3442 2
a3443 2
  c0 %= 65535;
  c1 %= 65535;
@


8.3.1.3
log
@In wcsfree() and wcsprt(), put wcsprm::err after the contained structs to
reflect the order in wcsprm.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.3.1.2 2024/05/20 08:57:49 mcalabre Exp mcalabre $
d1769 2
a1774 2
  wcserr_clear(&(wcs->err));

a2375 5
  // Contained structs.
  wcsprintf("        lin: (see below)\n");
  wcsprintf("        cel: (see below)\n");
  wcsprintf("        spc: (see below)\n");

d2381 5
@


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: wcs.c,v 8.1.1.1 2023/07/05 17:15:00 mcalabre Exp mcalabre $
d26 1
a47 2
const int WCSSET = 137;

d117 10
a133 6
// Internal helper functions, not for general use.
static int wcs_types(struct wcsprm *);
static int time_type(const char *);
static int time_code(const char *ctype, int nc);
static int wcs_units(struct wcsprm *);

a539 1
  wcs->flag  = 0;
a541 1

d543 3
a545 3
  wcs->lin.crpix  = wcs->crpix;
  wcs->lin.pc     = wcs->pc;
  wcs->lin.cdelt  = wcs->cdelt;
d680 1
a680 1
  wcs->dummy    =  0;
d685 3
a687 1
  return WCSERR_SUCCESS;
d732 1
a732 1
  return WCSERR_SUCCESS;
d1566 1
a1566 1
  if (wcs1->flag != WCSSET || wcs2->flag != WCSSET) {
a1770 2
  wcs->flag = 0;

d1775 3
a1777 1
  return WCSERR_SUCCESS;
d1789 1
a1789 1
    return WCSERR_SUCCESS;
d1792 1
a1792 1
  if (wcs->flag != WCSSET) {
d1882 6
a1887 1
  return WCSERR_SUCCESS;
d1897 1
a1897 1
    return WCSERR_SUCCESS;
d2003 1
a2003 1
  return WCSERR_SUCCESS;
d2013 1
a2013 1
    return WCSERR_SUCCESS;
d2022 1
a2022 1
  return WCSERR_SUCCESS;
d2025 33
d2084 1
a2084 1
  if (wcs->flag != WCSSET) {
d2086 1
a2086 1
    return WCSERR_SUCCESS;
d2089 1
d2099 1
a2099 1
  // Linear transformation.
d2110 1
a2110 1
  // Coordinate increment at reference point.
d2118 1
a2118 1
  // Coordinate value at reference point.
d2126 1
a2126 1
  // Coordinate units and type.
d2137 1
a2137 1
  // Celestial and spectral transformation parameters.
d2147 1
a2147 1
  // Parameter values.
d2163 1
a2163 1
  // Alternate linear transformations.
d2190 1
a2190 1
  // Auxiliary coordinate system information.
d2334 1
a2334 1
  // Additional auxiliary coordinate system information.
a2360 6
  WCSPRINTF_PTR("      types: ", wcs->types, "\n           ");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("%5d", wcs->types[i]);
  }
  wcsprintf("\n");

d2368 1
d2370 7
d2382 1
d2493 1
a2493 1
  return WCSERR_SUCCESS;
d2514 1
a2514 1
  return WCSERR_SUCCESS;
d2524 1
a2524 1
  if (wcs->flag != WCSSET) {
d2531 1
a2531 1
  return WCSERR_SUCCESS;
d2542 1
d2738 1
d2802 1
d2811 1
d2825 5
d2840 5
d2863 4
a2866 3
  wcs->lin.crpix  = wcs->crpix;
  wcs->lin.pc     = wcs->pc;
  wcs->lin.cdelt  = wcs->cdelt;
d2910 4
a2913 2
  for (int i = 0; i < naxis; i++) {
    wcsutil_null_fill(72, wcs->cname[i]);
d2942 4
a2945 1
  wcs->flag = WCSSET;
d2947 1
a2947 1
  return WCSERR_SUCCESS;
d2952 1
a2952 1
int wcs_types(struct wcsprm *wcs)
d3224 1
a3224 1
  return WCSERR_SUCCESS;
d3229 1
a3229 1
int time_type(const char *ctype)
d3278 1
a3278 1
int wcs_units(struct wcsprm *wcs)
d3333 4
a3336 2
        for (int j = 0; j < naxis; j++) {
          *(wcs->cd + i*naxis + j) *= scale;
d3347 99
a3445 1
  return WCSERR_SUCCESS;
d3469 1
a3469 1
  if (wcs->flag != WCSSET) {
d3505 3
a3507 3
    register const double *pix = pixcrd;
    register double *img = imgcrd;
    register int *statp = stat;
d3548 1
a3548 1
    register double *img, *wrl;
d3656 1
a3656 1
      int iso_x;
d3754 1
a3754 1
  if (wcs->flag != WCSSET) {
d3783 2
a3784 2
      register const double *wrl = world  + i;
      register double *img = imgcrd + i;
d3846 1
a3846 1
        register double *img = imgcrd;
d3960 3
a3962 3
    register const double *img = imgcrd;
    register double *pix = pixcrd;
    register int *statp = stat;
d4027 1
a4027 1
  if (wcs->flag != WCSSET) {
d4091 1
a4091 1
      if (dabs < tol) return WCSERR_SUCCESS;
d4105 1
a4105 1
      if (dabs < tol) return WCSERR_SUCCESS;
d4138 1
a4138 1
          if (dabs < tol) return WCSERR_SUCCESS;
d4183 1
a4183 1
            if (dabs < tol) return WCSERR_SUCCESS;
d4187 1
a4187 1
              if (dabs < tol2) return WCSERR_SUCCESS;
d4259 1
a4259 1
            if (d0m < tol) return WCSERR_SUCCESS;
d4272 1
a4272 1
            if (d1m < tol) return WCSERR_SUCCESS;
d4311 1
a4311 1
      if (dabs < tol) return WCSERR_SUCCESS;
d4325 1
a4325 1
      if (dabs < tol) return WCSERR_SUCCESS;
d4357 1
a4357 1
          if (dabs < tol) return WCSERR_SUCCESS;
d4402 1
a4402 1
            if (dabs < tol) return WCSERR_SUCCESS;
d4406 1
a4406 1
              if (dabs < tol2) return WCSERR_SUCCESS;
d4478 1
a4478 1
            if (d0m < tol) return WCSERR_SUCCESS;
d4491 1
a4491 1
            if (d1m < tol) return WCSERR_SUCCESS;
d4572 1
a4572 1
      return WCSERR_SUCCESS;
d4598 1
a4598 1
        return WCSERR_SUCCESS;
d4636 1
a4636 1
        return WCSERR_SUCCESS;
d4676 1
a4676 1
  if (wcs->flag != WCSSET) {
a4789 1
  wcs->flag = 0;
d4836 1
d4839 1
a4839 1
  return WCSERR_SUCCESS;
d4858 1
a4858 1
  if (wcs->flag != WCSSET) {
a4891 1
  wcs->flag = 0;
d4902 1
d4905 1
a4905 1
  return WCSERR_SUCCESS;
@


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


8.2.1.2
log
@Declared WCSSET to be static.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.1 2023/11/16 10:05:57 mcalabre Exp mcalabre $
d47 2
d118 6
a123 1
static const int WCSSET = 137;
a129 7

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

#ifndef signbit
#define signbit(X) ((X) < 0.0 ? 1 : 0)
#endif
@


8.2.1.3
log
@In wcsp2s(), ensure that iso_x is initialised for spectral and
logarithmic coordinates.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.2 2023/11/29 07:41:57 mcalabre Exp mcalabre $
d3491 1
a3491 1
      int iso_x = 0;
@


8.2.1.4
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2024, Mark Calabretta
d22 1
a22 1
  $Id: wcs.c,v 8.2.1.3 2023/12/20 12:42:38 mcalabre Exp mcalabre $
@


8.2.1.5
log
@Changes required to support bypass mode in wcsset().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.4 2024/04/02 14:01:58 mcalabre Exp mcalabre $
d537 1
d540 1
d684 1
a684 3
  wcs->flag = 0;

  return 0;
d729 1
a729 1
  return 0;
d1768 2
d1774 1
a1774 3
  wcs->flag = 0;

  return 0;
d1786 1
a1786 1
    return 0;
d1789 1
a1789 1
  if (abs(wcs->flag) != WCSSET) {
d1879 1
a1879 1
  return 0;
d1889 1
a1889 1
    return 0;
d1995 1
a1995 1
  return 0;
d2005 1
a2005 1
    return 0;
d2014 1
a2014 1
  return 0;
d2043 1
a2043 1
  if (abs(wcs->flag) != WCSSET) {
d2045 1
a2045 1
    return 0;
a2047 1
  // Parameters supplied...
d2057 1
a2057 1
  // ...linear transformation.
d2068 1
a2068 1
  // ...coordinate increment at reference point.
d2076 1
a2076 1
  // ...coordinate value at reference point.
d2084 1
a2084 1
  // ...coordinate units and type.
d2095 1
a2095 1
  // ...celestial and spectral transformation parameters.
d2105 1
a2105 1
  // ...parameter values.
d2121 1
a2121 1
  // ...alternate linear transformations.
d2148 1
a2148 1
  // ...auxiliary coordinate system information.
d2292 1
a2292 1
  // ...additional auxiliary coordinate system information.
a2332 1
  // Error handling.
a2337 1
  // Contained structs.
d2448 1
a2448 1
  return 0;
d2469 1
a2469 1
  return 0;
d2479 1
a2479 1
  if (abs(wcs->flag) != WCSSET) {
d2486 1
a2486 1
  return 0;
a2496 1
  if (wcs->flag == -WCSSET) return 0;
d2880 1
a2880 1
  wcs->flag = (wcs->flag == 1) ? -WCSSET : WCSSET;
d2882 1
a2882 1
  return 0;
d2887 1
a2887 1
static int wcs_types(struct wcsprm *wcs)
d3159 1
a3159 1
  return 0;
d3164 1
a3164 1
static int time_type(const char *ctype)
d3213 1
a3213 1
static int wcs_units(struct wcsprm *wcs)
d3280 1
a3280 1
  return 0;
d3304 1
a3304 1
  if (abs(wcs->flag) != WCSSET) {
d3340 3
a3342 3
    const double *pix = pixcrd;
    double *img = imgcrd;
    int *statp = stat;
d3383 1
a3383 1
    double *img, *wrl;
d3589 1
a3589 1
  if (abs(wcs->flag) != WCSSET) {
d3618 2
a3619 2
      const double *wrl = world  + i;
      double *img = imgcrd + i;
d3681 1
a3681 1
        double *img = imgcrd;
d3795 3
a3797 3
    const double *img = imgcrd;
    double *pix = pixcrd;
    int *statp = stat;
d3862 1
a3862 1
  if (abs(wcs->flag) != WCSSET) {
d3926 1
a3926 1
      if (dabs < tol) return 0;
d3940 1
a3940 1
      if (dabs < tol) return 0;
d3973 1
a3973 1
          if (dabs < tol) return 0;
d4018 1
a4018 1
            if (dabs < tol) return 0;
d4022 1
a4022 1
              if (dabs < tol2) return 0;
d4094 1
a4094 1
            if (d0m < tol) return 0;
d4107 1
a4107 1
            if (d1m < tol) return 0;
d4146 1
a4146 1
      if (dabs < tol) return 0;
d4160 1
a4160 1
      if (dabs < tol) return 0;
d4192 1
a4192 1
          if (dabs < tol) return 0;
d4237 1
a4237 1
            if (dabs < tol) return 0;
d4241 1
a4241 1
              if (dabs < tol2) return 0;
d4313 1
a4313 1
            if (d0m < tol) return 0;
d4326 1
a4326 1
            if (d1m < tol) return 0;
d4407 1
a4407 1
      return 0;
d4433 1
a4433 1
        return 0;
d4471 1
a4471 1
        return 0;
d4511 1
a4511 1
  if (abs(wcs->flag) != WCSSET) {
d4625 1
a4625 1
  wcs->flag = (wcs->flag == WCSSET) ? 0 : 1;
d4674 1
a4674 1
  return 0;
d4693 1
a4693 1
  if (abs(wcs->flag) != WCSSET) {
d4727 1
a4727 1
  wcs->flag = (wcs->flag == WCSSET) ? 0 : 1;
d4740 1
a4740 1
  return 0;
@


8.2.1.6
log
@Added wcsenq().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.5 2024/05/08 08:59:51 mcalabre Exp mcalabre $
a2016 29
//----------------------------------------------------------------------------

int wcsenq(const struct wcsprm *wcs, int enquiry)

{
  static const char *function = "wcsenq";

  // Initialize.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  int answer = 0;

  if (enquiry & WCSENQ_MEM) {
    if (wcs->m_flag != WCSSET) return 0;
    answer = 1;
  }

  if (enquiry & WCSENQ_SET) {
    if (abs(wcs->flag) != WCSSET) return 0;
    answer = 1;
  }

  if (enquiry & WCSENQ_BYP) {
    if (wcs->flag != -WCSSET) return 0;
    answer = 1;
  }

  return answer;
}
@


8.2.1.7
log
@Attended to compiler warnings about unused variables.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.6 2024/05/08 15:16:27 mcalabre Exp mcalabre $
d2022 2
@


8.2.1.8
log
@In wcsenq(), the wcsprm struct is also in bypass mode, though unset, if
wcsprm::flag == 1.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.7 2024/05/08 15:39:34 mcalabre Exp mcalabre $
d2038 1
a2038 1
    if (wcs->flag != 1 && wcs->flag != -WCSSET) return 0;
@


8.2.1.9
log
@In wcscompare(), support bypass mode in wcsset().
In wcsset(), set wcscel->flag = 0 explicitly before calling celset() - a
safety measure to protect against celjprm in bypass mode, which shouldn't
happen.  Likewise for wcsspc->flag and wcs->tab[i].flag.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.8 2024/05/10 14:38:48 mcalabre Exp mcalabre $
d540 3
a542 3
  wcs->lin.crpix = wcs->crpix;
  wcs->lin.pc    = wcs->pc;
  wcs->lin.cdelt = wcs->cdelt;
d1563 1
a1563 1
  if (abs(wcs1->flag) != WCSSET || abs(wcs2->flag) != WCSSET) {
a2722 1
    wcscel->flag = 0;
a2785 1
    wcsspc->flag = 0;
a2793 1
    wcs->tab[itab].flag = 0;
d2835 3
a2837 4
  wcs->lin.crpix = wcs->crpix;
  wcs->lin.pc    = wcs->pc;
  wcs->lin.cdelt = wcs->cdelt;
  wcs->lin.flag  = 0;
d4656 1
a4702 1
  wcs->flag = (wcs->flag == -WCSSET) ? 1 : 0;
d4758 1
a4768 1
  wcs->flag = (wcs->flag == -WCSSET) ? 1 : 0;
@


8.2.1.10
log
@Added support for wcsprm::chksum, including a new helper function,
wcs_chksum(), used by wcsset() and wcsenq().  In wcsset(), guard against
wcsprm::cd, wcsprm::crota, or wcsprm::cname being null pointers.  Likewise,
in wcs_units(), guard against wcsprm::cd == 0x0.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.9 2024/05/13 05:09:41 mcalabre Exp mcalabre $
a122 1
static int wcs_chksum(const struct wcsprm *wcs);
d677 1
a677 1
  wcs->chksum   =  0;
a1878 5
  // Reset the struct (to store the new checksum).
  int status;
  wcs->flag = (wcs->flag == -WCSSET) ? 1 : 0;
  if ((status = wcsset(wcs))) return status;

a2041 6
  if (enquiry & WCSENQ_CHK) {
    if (abs(wcs->flag) != WCSSET) return 0;
    if (wcs->chksum != wcs_chksum(wcs)) return 0;
    answer = 1;
  }

d2347 6
a2359 7
  wcsprintf("     chksum:%12d\n", wcs->chksum);

  WCSPRINTF_PTR("      types: ", wcs->types, "\n           ");
  for (int i = 0; i < wcs->naxis; i++) {
    wcsprintf("%5d", wcs->types[i]);
  }
  wcsprintf("\n");
a2809 5
      if (!wcs->cd) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
          "ALTLIN == %d but CDij absent", wcs->altlin);
      }

a2819 5
      if (!wcs->crota) {
        return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
          "ALTLIN == %d but CROTAj absent", wcs->altlin);
      }

d2885 2
a2886 4
  if (wcs->cname) {
    for (int i = 0; i < naxis; i++) {
      wcsutil_null_fill(72, wcs->cname[i]);
    }
a2914 3
  // Compute and store the checksum.
  wcs->chksum = wcs_chksum(wcs);

d3303 2
a3304 4
        if (wcs->cd) {
          for (int j = 0; j < naxis; j++) {
            *(wcs->cd + i*naxis + j) *= scale;
          }
a3315 124
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int wcs_chksum(const struct wcsprm *wcs)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  // data[] is treated as a byte-array.
  uint16_t data[2048];
  uint8_t *datap = (uint8_t *)data;

  size_t  naxis = wcs->naxis;
  size_t    szi = sizeof(int);
  size_t    szd = sizeof(double);
  size_t nszc72 = naxis * sizeof(char [72]);
  size_t   nszd = naxis *  szd;
  size_t  nnszd = naxis * nszd;

  // wcsprm::naxis.
  memcpy(datap, &wcs->naxis, szi);
  datap += szi;

  // wcsprm::crpix[].
  memcpy(datap, wcs->crpix, nszd);
  datap += nszd;

  // wcsprm::pc[].
  memcpy(datap, wcs->pc, nnszd);
  datap += nnszd;

  // wcsprm::cdelt[].
  memcpy(datap, wcs->cdelt, nszd);
  datap += nszd;

  // wcsprm::crval[].
  memcpy(datap, wcs->crval, nszd);
  datap += nszd;

  // wcsprm::cunit[].
  memcpy(datap, wcs->cunit, nszc72);
  datap += nszc72;

  // wcsprm::ctype[].
  memcpy(datap, wcs->ctype, nszc72);
  datap += nszc72;

  // wcsprm::lonpole.
  memcpy(datap, &wcs->lonpole, szd);
  datap += szd;

  // wcsprm::latpole.
  memcpy(datap, &wcs->latpole, szd);
  datap += szd;

  // wcsprm::restfrq.
  memcpy(datap, &wcs->restfrq, szd);
  datap += szd;

  // wcsprm::restwav.
  memcpy(datap, &wcs->restwav, szd);
  datap += szd;

  // wcsprm::npv.
  memcpy(datap, &wcs->npv, szi);
  datap += szi;

  // wcsprm::pv[].
  if (wcs->pv) {
    size_t nszpv = wcs->npvmax * sizeof(struct pvcard);
    memcpy(datap, &wcs->pv, nszpv);
    datap += nszpv;
  }

  // wcsprm::nps.
  memcpy(datap, &wcs->nps, szi);
  datap += szi;

  // wcsprm::ps[].
  if (wcs->ps) {
    size_t nszps = wcs->npsmax * sizeof(struct pscard);
    memcpy(datap, &wcs->ps, nszps);
    datap += nszps;
  }

  // wcsprm::cd.
  if (wcs->cd) {
    memcpy(datap, wcs->pc, nnszd);
    datap += nnszd;
  }

  // wcsprm::crota[].
  if (wcs->crota) {
    memcpy(datap, wcs->crota, nszd);
    datap += nszd;
  }

  // wcsprm::altlin.
  memcpy(datap, &wcs->altlin, szi);
  datap += szi;

  // wcsprm::ntab.
  memcpy(datap, &wcs->ntab, szi);
  datap += szi;

  // wcsprm::nwtb.
  memcpy(datap, &wcs->nwtb, szi);
  datap += szi;

  // wcsprm::tab (an address).
  size_t szp = sizeof(struct tabprm *);
  memcpy(datap, &wcs->tab, szp);
  datap += szp;

  // wcsprm::wtb (an address).
  szp = sizeof(struct wtbarr *);
  memcpy(datap, &wcs->wtb, szp);
  datap += szp;

  // Count of 16-bit words.
  size_t len = ((uint16_t *)datap - data);

  return wcsutil_fletcher32(data, len);
@


8.2.1.11
log
@Moved wcsutil_fletcher32() from wcsutil.{h,c} to here as a static function,
wcs_fletcher32(), for the sole use of wcs_chksum().  Changed its method of
operation so that it calculates the checksum incrementally.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 8.2.1.10 2024/05/13 14:33:51 mcalabre Exp mcalabre $
a25 1
#include <stdint.h>
a123 1
static int wcs_fletcher32(int chksum, const void *data, size_t len);
d3355 4
d3366 27
a3392 1
  int chksum = 0;
d3394 19
a3412 14
  // The checksum is computed incrementally - the result from one invokation
  // forms the starting value for the next one.
  chksum = wcs_fletcher32(chksum, &wcs->naxis,   szi);
  chksum = wcs_fletcher32(chksum, wcs->crpix,   nszd);
  chksum = wcs_fletcher32(chksum, wcs->pc,     nnszd);
  chksum = wcs_fletcher32(chksum, wcs->cdelt,   nszd);
  chksum = wcs_fletcher32(chksum, wcs->crval,   nszd);
  chksum = wcs_fletcher32(chksum, wcs->cunit,   nszc72);
  chksum = wcs_fletcher32(chksum, wcs->ctype,   nszc72);
  chksum = wcs_fletcher32(chksum, &wcs->lonpole, szd);
  chksum = wcs_fletcher32(chksum, &wcs->latpole, szd);
  chksum = wcs_fletcher32(chksum, &wcs->restfrq, szd);
  chksum = wcs_fletcher32(chksum, &wcs->restwav, szd);
  chksum = wcs_fletcher32(chksum, &wcs->npv,     szi);
d3414 1
d3417 2
a3418 1
    chksum = wcs_fletcher32(chksum, &wcs->pv, nszpv);
d3421 3
a3423 1
  chksum = wcs_fletcher32(chksum, &wcs->nps, szi);
d3425 1
d3428 2
a3429 1
    chksum = wcs_fletcher32(chksum, &wcs->ps, nszps);
d3432 1
d3434 2
a3435 1
    chksum = wcs_fletcher32(chksum, wcs->pc, nnszd);
d3438 1
d3440 2
a3441 1
    chksum = wcs_fletcher32(chksum, wcs->crota, nszd);
d3444 7
a3450 5
  chksum = wcs_fletcher32(chksum, &wcs->altlin, szi);
  chksum = wcs_fletcher32(chksum, &wcs->ntab, szi);
  chksum = wcs_fletcher32(chksum, &wcs->nwtb, szi);
  chksum = wcs_fletcher32(chksum, &wcs->tab, sizeof(struct tabprm *));
  chksum = wcs_fletcher32(chksum, &wcs->wtb, sizeof(struct wtbarr *));
d3452 3
a3454 2
  return chksum;
}
d3456 4
a3459 1
// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
d3461 4
a3464 29
// Compute the Fletcher-32 checksum for a sequence of bytes.  The algorithm is
// described in https://en.wikipedia.org/wiki/Fletcher's_checksum.
//
// Given:
//   chksum    int      Checksum from a previous invokation, forming the
//                      starting value for this one.
//
//   data      const void *
//                      Data array, treated as an array of uint16_t.
//
//   len       size_t   Length of the data array in bytes.  Must be even and
//                      less than 259200 (no checks are made).
//
// Function return value:
//             int      Fletcher-32 checksum.

static int wcs_fletcher32(int chksum, const void *data, size_t len)

{
  const uint16_t *datap = (const uint16_t *)data;

  uint32_t c0 = ((uint32_t)chksum & 65535);
  uint32_t c1 = ((uint32_t)chksum >> 16);

  while (len) {
    c0 += *datap++;
    c1 += c0;
    len -= 2;
  }
d3466 2
a3467 2
  c0 &= 65535;
  c1 &= 65535;
d3469 1
a3469 1
  return (int)(c1 << 16 | c0);
@


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: wcs.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: wcs.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: wcs.c,v 7.13.1.4 2023/07/01 06:07:46 mcalabre Exp mcalabre $
@


8.0.1.1
log
@WCSLIB 8.0 development branch.
@
text
@d22 1
a22 1
  $Id: wcs.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: wcs.c,v 7.12.1.1 2022/09/09 05:00:36 mcalabre Exp mcalabre $
d677 1
d679 1
d722 7
d1277 7
d1630 9
d2300 7
d2330 1
d2905 1
d3014 1
@


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


7.13.1.2
log
@Added wcsprm::time to record the time axis number (along with lng,lat,spec).
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.13.1.1 2022/10/07 03:45:47 mcalabre Exp mcalabre $
a676 1
  wcs->time = -1;
a677 1
  wcs->dummy    =  0;
a2297 1
  wcsprintf("       time: %d\n", wcs->time);
a2871 1
  wcs->time = -1;
a2979 1
        if (wcs->time < 0) wcs->time = i;
@


7.13.1.3
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2023, Mark Calabretta
d22 1
a22 1
  $Id: wcs.c,v 7.13.1.2 2023/06/03 05:37:07 mcalabre Exp $
@


7.13.1.4
log
@Support planetary keywords A_RADIUS, B_RADIUS, C_RADIUS, BLON_OBS, BLAT_OBS,
and BDIS_OBS in auxprm.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.13.1.3 2023/06/15 04:17:19 mcalabre Exp mcalabre $
a721 7
  aux->a_radius = UNDEFINED;
  aux->b_radius = UNDEFINED;
  aux->c_radius = UNDEFINED;
  aux->blon_obs = UNDEFINED;
  aux->blat_obs = UNDEFINED;
  aux->bdis_obs = UNDEFINED;

a1269 7

    wcsdst->aux->a_radius = wcssrc->aux->a_radius;
    wcsdst->aux->b_radius = wcssrc->aux->b_radius;
    wcsdst->aux->c_radius = wcssrc->aux->c_radius;
    wcsdst->aux->blon_obs = wcssrc->aux->blon_obs;
    wcsdst->aux->blat_obs = wcssrc->aux->blat_obs;
    wcsdst->aux->bdis_obs = wcssrc->aux->bdis_obs;
a1615 9

      if (!wcsutil_dblEq(1, tol, &wcs1->aux->a_radius, &wcs2->aux->a_radius) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->b_radius, &wcs2->aux->b_radius) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->c_radius, &wcs2->aux->c_radius) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->blon_obs, &wcs2->aux->blon_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->blat_obs, &wcs2->aux->blat_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->bdis_obs, &wcs2->aux->bdis_obs)) {
        return 0;
      }
a2276 7

    wcsprt_auxd("a_radius", wcs->aux->a_radius);
    wcsprt_auxd("b_radius", wcs->aux->b_radius);
    wcsprt_auxd("c_radius", wcs->aux->c_radius);
    wcsprt_auxd("blon_obs", wcs->aux->blon_obs);
    wcsprt_auxd("blat_obs", wcs->aux->blat_obs);
    wcsprt_auxd("bdis_obs", wcs->aux->bdis_obs);
@


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: wcs.c,v 7.11.1.4 2022/09/09 02:12:08 mcalabre Exp mcalabre $
@


7.12.1.1
log
@WCSLIB 7.12 development branch.
@
text
@d22 1
a22 1
  $Id: wcs.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: wcs.c,v 7.10.1.2 2022/04/26 05:43:48 mcalabre Exp mcalabre $
d128 1
a840 5
        } else if (strcmp(ctypei, "CUBEFACE") == 0) {
          if (!cubeface) {
            continue;
          }

d857 5
d867 2
a868 2
        } else if (strcmp(ctypei, "TIME") == 0 || time_type(ctypei)) {
          if (!time) {
d2978 1
a2978 1
      } else if (strcmp(ctypei, "TIME") == 0 || time_type(ctypei)) {
d3133 39
a3171 14
  if (strcmp(ctype, "UTC") == 0) return 1;
  if (strcmp(ctype, "TAI") == 0) return 1;
  if (strcmp(ctype, "IAT") == 0) return 1;
  if (strcmp(ctype, "TT")  == 0) return 1;
  if (strcmp(ctype, "TDB") == 0) return 1;
  if (strcmp(ctype, "TDT") == 0) return 1;
  if (strcmp(ctype, "GPS") == 0) return 1;
  if (strcmp(ctype, "TCB") == 0) return 1;
  if (strcmp(ctype, "TCG") == 0) return 1;
  if (strcmp(ctype, "GMT") == 0) return 1;
  if (strcmp(ctype, "UT1") == 0) return 1;
  if (strcmp(ctype, "UT")  == 0) return 1;
  if (strcmp(ctype, "ET")  == 0) return 1;
  if (strcmp(ctype, "LOCAL") == 0) return 1;
d3268 1
a3268 1
  int status;
a3279 5
  // Apply pixel-to-world linear transformation.
  if ((status = linp2x(&(wcs->lin), ncoord, nelem, pixcrd, imgcrd))) {
    return wcserr_set(WCS_ERRMSG(wcs_linerr[status]));
  }

d3290 51
d3413 2
a3414 1
      int iso_x, iso_y;
d3417 9
a3425 6
      if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
        nx = 1;
        ny = ncoord;
      }
      if ((iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat))) {
        ny = 1;
d3429 7
a3435 9
      int istat;
      if ((istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                          imgcrd+wcs->lat, phi, theta, world+i,
                          world+wcs->lat, istatp))) {
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
          if (status != WCSERR_BAD_PIX) {
            goto cleanup;
          }
d3448 2
a3449 1
      if (istat == 5) {
d3455 1
a3455 1
      // Check for constant x.
d3458 5
a3462 2
      if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
        nx = 1;
d3494 2
a3495 1
      if (istat == 3) {
a3507 1

d3510 1
d3512 4
a3515 6
      } else {
        int bits = 0;
        for (int m = 0; m < wcs->tab[itab].M; m++) {
          bits |= 1 << wcs->tab[itab].map[m];
        }
        wcsutil_setBit(ncoord, istatp, bits, stat);
d3517 1
d3553 1
a3553 1
  int status;
a3569 1
  status = 0;
d3594 2
a3595 1
      int isolng, isolat;
d3599 8
a3606 6
      if ((isolng = wcsutil_allEq(ncoord, nelem, world+i))) {
        nlng = 1;
        nlat = ncoord;
      }
      if ((isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat))) {
        nlat = 1;
d3610 7
a3616 9
      int istat;
      if ((istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                          world+wcs->lat, phi, theta, imgcrd+i,
                          imgcrd+wcs->lat, istatp))) {
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
          if (status != WCSERR_BAD_WORLD) {
            goto cleanup;
          }
d3629 2
a3630 1
      if (istat == CELERR_BAD_WORLD) {
d3672 2
a3673 2
      // Check for constancy.
      int isospec;
d3675 5
a3679 2
      if ((isospec = wcsutil_allEq(ncoord, nelem, world+i))) {
        nwrld = 1;
d3711 2
a3712 1
      if (istat == 4) {
d3726 3
a3728 6
      if (status == WCSERR_BAD_WORLD) {
        int bits = 0;
        for (int m = 0; m < wcs->tab[itab].M; m++) {
          bits |= 1 << wcs->tab[itab].map[m];
        }
        wcsutil_setBit(ncoord, istatp, bits, stat);
d3730 3
a3732 2
      } else {
        goto cleanup;
d3734 1
d3747 46
a3792 4
  int istat;
  if ((istat = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd))) {
    status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
    goto cleanup;
@


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


7.11.1.2
log
@When used by wcssub(), time_type() must account for time axes with the
algorithm codes -TAB and -LOG.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.11.1.1 2022/04/26 06:15:32 mcalabre Exp mcalabre $
a127 1
static int time_code(const char *ctype, int nc);
d840 5
a860 5
        } else if (time_type(ctypei)) {
          if (!time) {
            continue;
          }

d866 2
a867 2
        } else if (strcmp(ctypei, "CUBEFACE") == 0) {
          if (!cubeface) {
d2977 1
a2977 1
      } else if (time_type(ctypei)) {
d3132 14
a3145 39
  if (strncmp(ctype, "TIME", 4) == 0) return time_code(ctype, 4);
  if (strncmp(ctype, "UTC",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TAI",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "IAT",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TT",   2) == 0) return time_code(ctype, 2);
  if (strncmp(ctype, "TDB",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TDT",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "GPS",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TCB",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "TCG",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "GMT",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "UT1",  3) == 0) return time_code(ctype, 3);
  if (strncmp(ctype, "UT",   2) == 0) return time_code(ctype, 2);
  if (strncmp(ctype, "ET",   2) == 0) return time_code(ctype, 2);
  if (strncmp(ctype, "LOCAL",5) == 0) return 1;

  return 0;
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

static int time_code(const char *ctype, int nc)

{
  // If no algorithm code then we're finished.
  if (*(ctype+nc) == '\0') return 1;

  // Check the correct number of hyphens for things like "TT---TAB".
  while (nc < 4) {
    if (*(ctype+nc) != '-') return 0;
    nc++;
  }

  // Is it a code applicable to time-like axes?
  const char *code = ctype + 4;
  if (*code == '-') {
    if (strncmp(code, "-LOG", 5) == 0) return 1;
    if (strncmp(code, "-TAB", 5) == 0) return 1;
  }
@


7.11.1.3
log
@In wcsp2s() and wcss2p(), handle status returns relating to distortion
functions properly, specifically with respect to setting the stat[] vector.
Also tweaked up the code handling the stat[] vector for other axis types.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.11.1.2 2022/09/03 08:06:19 mcalabre Exp mcalabre $
d3268 1
a3268 1
  int status = 0;
d3280 5
a3294 51
  // Apply pixel-to-world linear transformation.
  struct linprm *lin = &(wcs->lin);
  if (!(lin->dispre || lin->disseq)) {
    // No distortions present, do vector call.
    int istat = linp2x(lin, ncoord, nelem, pixcrd, imgcrd);
    if (istat) {
      // If one fails then all fail.
      status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
      goto cleanup;
    }

  } else {
    // Distortions present, get the status return for each coordinate.
    int disaxes = 0;

    register const double *pix = pixcrd;
    register double *img = imgcrd;
    register int *statp = stat;
    for (int k = 0 ; k < ncoord; k++, pix += nelem, img += nelem, statp++) {
      int istat = linp2x(lin, 1, nelem, pix, img);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
        if (status != WCSERR_BAD_PIX) {
          goto cleanup;
        }

        if (disaxes == 0) {
          // Which axes have distortions?
          struct disprm *dispre = lin->dispre;
          struct disprm *disseq = lin->disseq;
          for (int i = 0; i < wcs->naxis; i++) {
            if (dispre && dispre->disp2x[i]) {
              disaxes |= (1 << i);
            } else if (disseq && disseq->disp2x[i]) {
              disaxes |= (1 << i);
            }
          }

          if (disaxes == 0) {
            // Shouldn't happen.
            disaxes = (2 << wcs->naxis) - 1;
          }
        }

        // WCSERR_BAD_PIX stat[] vector accounting.
        *statp = disaxes;
      }
    }
  }


d3379 9
a3387 7
      int istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                         imgcrd+wcs->lat, phi, theta, world+i,
                         world+wcs->lat, istatp);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
        if (status != WCSERR_BAD_PIX) {
          goto cleanup;
d3400 1
a3400 2
      // WCSERR_BAD_PIX stat[] vector accounting.
      if (istat) {
d3406 1
a3406 1
      // Spectral and logarithmic coordinates; check for constant x.
d3442 1
a3442 2
      // WCSERR_BAD_PIX stat[] vector accounting.
      if (istat) {
d3455 1
a3457 1
      }
d3459 6
a3464 4
      // WCSERR_BAD_PIX stat[] vector accounting.
      int bits = 0;
      for (int m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
a3465 1
      wcsutil_setBit(ncoord, istatp, bits, stat);
d3501 1
a3501 1
  int status = 0;
d3518 1
d3556 9
a3564 7
      int istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                         world+wcs->lat, phi, theta, imgcrd+i,
                         imgcrd+wcs->lat, istatp);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
        if (status != WCSERR_BAD_WORLD) {
          goto cleanup;
d3577 1
a3577 2
      // WCSERR_BAD_WORLD stat[] vector accounting.
      if (istat) {
d3619 1
a3619 1
      // Spectral and logarithmic coordinates; check for constancy.
d3655 1
a3655 2
      // WCSERR_BAD_WORLD stat[] vector accounting.
      if (istat) {
d3669 8
a3676 1
      if (status != WCSERR_BAD_WORLD) {
a3678 6

      int bits = 0;
      for (int m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
      }
      wcsutil_setBit(ncoord, istatp, bits, stat);
d3691 4
a3694 46
  struct linprm *lin = &(wcs->lin);
  if (!(lin->dispre || lin->disseq)) {
    // No distortions present, do vector call.
    int istat = linx2p(lin, ncoord, nelem, imgcrd, pixcrd);
    if (istat) {
      status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
      goto cleanup;
    }

  } else {
    // Distortions present, get the status return for each coordinate.
    int disaxes = 0;

    register const double *img = imgcrd;
    register double *pix = pixcrd;
    register int *statp = stat;
    for (int k = 0 ; k < ncoord; k++, pix += nelem, img += nelem, statp++) {
      int istat = linx2p(lin, 1, nelem, img, pix);
      if (istat) {
        status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
        if (status != WCSERR_BAD_WORLD) {
          goto cleanup;
        }

        if (disaxes == 0) {
          // Which axes have distortions?
          struct disprm *dispre = lin->dispre;
          struct disprm *disseq = lin->disseq;
          for (int i = 0; i < wcs->naxis; i++) {
            if (dispre && dispre->disp2x[i]) {
              disaxes |= (1 << i);
            } else if (disseq && disseq->disp2x[i]) {
              disaxes |= (1 << i);
            }
          }

          if (disaxes == 0) {
            // Shouldn't happen.
            disaxes = (2 << wcs->naxis) - 1;
          }
        }

        // WCSERR_BAD_WORLD stat[] vector accounting.
        *statp = disaxes;
      }
    }
@


7.11.1.4
log
@In wcsp2s() and wcss2p(), short-circuit the test for iso_x, iso_y, isolng,
and isolat if ncoord == 1.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.11.1.3 2022/09/08 04:03:12 mcalabre Exp mcalabre $
d3413 1
a3413 2
      int iso_x = 0;
      int iso_y = 0;
d3416 6
a3421 9

      if (ncoord > 1) {
        if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
          nx = 1;
          ny = ncoord;
        }
        if ((iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat))) {
          ny = 1;
        }
d3454 2
a3455 5

      if (ncoord > 1) {
        if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
          nx = 1;
        }
d3587 1
a3587 2
      int isolng = 0;
      int isolat = 0;
d3591 6
a3596 8
      if (ncoord > 1) {
        if ((isolng = wcsutil_allEq(ncoord, nelem, world+i))) {
          nlng = 1;
          nlat = ncoord;
        }
        if ((isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat))) {
          nlat = 1;
        }
d3663 1
a3663 1
      int isospec = 0;
d3665 2
a3666 5

      if (ncoord > 1) {
        if ((isospec = wcsutil_allEq(ncoord, nelem, world+i))) {
          nwrld = 1;
        }
@


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: wcs.c,v 7.9.1.1 2022/03/25 15:16:40 mcalabre Exp mcalabre $
d1302 1
@


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


7.10.1.2
log
@In wcssub(), set tab->flag = -1 before invoking tabcpy().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.10.1.1 2022/04/23 14:26:54 mcalabre Exp mcalabre $
a1301 1
        tab->flag = -1;
@


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: wcs.c,v 7.8.1.2 2022/03/25 14:58:54 mcalabre Exp mcalabre $
@


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


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: wcs.c,v 7.7.1.6 2022/03/25 06:05:59 mcalabre Exp mcalabre $
d3131 14
a3144 14
  if (strcmp(ctype, "UTC")) return 1;
  if (strcmp(ctype, "TAI")) return 1;
  if (strcmp(ctype, "IAT")) return 1;
  if (strcmp(ctype, "TT"))  return 1;
  if (strcmp(ctype, "TDB")) return 1;
  if (strcmp(ctype, "TDT")) return 1;
  if (strcmp(ctype, "GPS")) return 1;
  if (strcmp(ctype, "TCB")) return 1;
  if (strcmp(ctype, "TCG")) return 1;
  if (strcmp(ctype, "GMT")) return 1;
  if (strcmp(ctype, "UT1")) return 1;
  if (strcmp(ctype, "UT"))  return 1;
  if (strcmp(ctype, "ET"))  return 1;
  if (strcmp(ctype, "LOCAL")) return 1;
@


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


7.8.1.2
log
@Fixed the string comparison tests in time_type().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.8.1.1 2022/03/25 06:14:14 mcalabre Exp mcalabre $
d3131 14
a3144 14
  if (strcmp(ctype, "UTC") == 0) return 1;
  if (strcmp(ctype, "TAI") == 0) return 1;
  if (strcmp(ctype, "IAT") == 0) return 1;
  if (strcmp(ctype, "TT")  == 0) return 1;
  if (strcmp(ctype, "TDB") == 0) return 1;
  if (strcmp(ctype, "TDT") == 0) return 1;
  if (strcmp(ctype, "GPS") == 0) return 1;
  if (strcmp(ctype, "TCB") == 0) return 1;
  if (strcmp(ctype, "TCG") == 0) return 1;
  if (strcmp(ctype, "GMT") == 0) return 1;
  if (strcmp(ctype, "UT1") == 0) return 1;
  if (strcmp(ctype, "UT")  == 0) return 1;
  if (strcmp(ctype, "ET")  == 0) return 1;
  if (strcmp(ctype, "LOCAL") == 0) return 1;
@


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: wcs.c,v 7.6.1.2 2021/07/01 08:33:22 mcalabre Exp mcalabre $
d127 1
d156 1
a156 3
  int i, j, k, status;
  double *cd;
  struct wcserr **err;
d169 1
a169 1
  err = &(wcs->err);
d550 1
a550 1
  for (i = 0; i < naxis; i++) {
d556 1
a556 1
  for (i = 0; i < naxis; i++) {
d572 1
a572 1
  for (k = 0; k < wcs->npvmax; k++) {
d579 1
a579 1
  for (k = 0; k < wcs->npsmax; k++) {
d586 3
a588 3
  cd = wcs->cd;
  for (i = 0; i < naxis; i++) {
    for (j = 0; j < naxis; j++) {
d592 1
a592 1
  for (i = 0; i < naxis; i++) {
d603 1
a603 1
  for (i = 0; i < naxis; i++) {
a692 3
  struct auxprm *aux;
  struct wcserr **err;

d695 1
a695 1
  err = &(wcs->err);
d712 1
a712 1
  aux = wcs->aux;
d735 1
a735 10
  char *c, ctypei[16], ctmp[16], *fp;
  int  axis, axmap[32], cubeface, dealloc, dummy, i, idp, itab, *itmp = 0x0,
       j, jhat, k, latitude, longitude, m, *map, msub, naxis, ndp, ndpmax,
       Nhat, npv, npvmax, nps, npsmax, ntmp, other, spectral, status, stokes;
  const double *srcp;
  double *dstp;
  struct tabprm *tab;
  struct disprm *dissrc, *disdst;
  struct dpkey  *dpsrc,  *dpdst;
  struct wcserr **err;
d739 1
a739 1
  err = &(wcsdst->err);
d742 1
d748 1
d757 2
a758 1
  ntmp = (*nsub <= naxis) ? naxis : *nsub;
d763 1
d771 1
a771 1
    for (i = 0; i < naxis; i++) {
d781 3
a783 3
  msub = 0;
  for (j = 0; j < *nsub; j++) {
    axis = axes[j];
d787 1
a787 1
      k = abs(axis) & 0xFF;
d789 6
a794 5
      longitude = k & WCSSUB_LONGITUDE;
      latitude  = k & WCSSUB_LATITUDE;
      cubeface  = k & WCSSUB_CUBEFACE;
      spectral  = k & WCSSUB_SPECTRAL;
      stokes    = k & WCSSUB_STOKES;
d796 1
d803 1
d806 2
a807 1
      for (i = 0; i < naxis; i++) {
d812 1
a812 1
        c = ctypei + 8;
d866 5
d876 1
d887 1
d911 1
a911 1
  for (i = 0; i < *nsub; i++) {
d921 2
a922 2
  map = itmp;
  for (i = 0; i < naxis; i++) {
d926 1
a926 1
  for (i = 0; i < *nsub; i++) {
d935 4
a938 3
  srcp = wcssrc->pc;
  for (i = 0; i < naxis; i++) {
    for (j = 0; j < naxis; j++) {
d942 2
a943 1
        status = wcserr_set(WCS_ERRMSG(WCSERR_NON_SEPARABLE));
d949 2
d953 3
a955 2
  ndpmax = 0;
  for (m = 0; m < 2; m++) {
d962 1
a962 1
    ndp = 0;
d964 1
a964 1
      for (j = 0; j < naxis; j++) {
d968 2
a969 1
        for (jhat = 0; jhat < 32; jhat++) {
d973 3
a975 3
        Nhat = 0;
        dpsrc = dissrc->dp;
        for (idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
d979 1
d988 1
d1001 1
a1001 1
        for (jhat = 0; jhat < Nhat; jhat++) {
d1011 2
a1012 1
            status = wcserr_set(WCS_ERRMSG(WCSERR_NON_SEPARABLE));
d1024 3
a1026 3
  npvmax = 0;
  for (m = 0; m < wcssrc->npv; m++) {
    i = wcssrc->pv[m].i;
d1033 3
a1035 3
  npsmax = 0;
  for (m = 0; m < wcssrc->nps; m++) {
    i = wcssrc->ps[m].i;
d1044 2
a1045 1
  for (m = 0; m < 2; m++) {
d1073 1
a1073 1
  for (j = 0; j < *nsub; j++, dstp++) {
d1075 1
a1075 1
      k = axes[j] - 1;
d1082 2
a1083 2
  for (i = 0; i < *nsub; i++) {
    for (j = 0; j < *nsub; j++, dstp++) {
d1085 1
a1085 1
        k = (axes[i]-1)*naxis + (axes[j]-1);
d1093 1
a1093 1
  for (i = 0; i < *nsub; i++, dstp++) {
d1095 1
a1095 1
      k = axes[i] - 1;
d1103 1
a1103 1
  for (i = 0; i < *nsub; i++, dstp++) {
d1105 1
a1105 1
      k = axes[i] - 1;
d1111 1
a1111 1
  for (i = 0; i < *nsub; i++) {
d1113 1
a1113 1
      k = axes[i] - 1;
d1126 3
a1128 3
  npv = 0;
  for (m = 0; m < wcssrc->npv; m++) {
    i = wcssrc->pv[m].i;
d1142 3
a1144 3
  nps = 0;
  for (m = 0; m < wcssrc->nps; m++) {
    i = wcssrc->ps[m].i;
d1157 2
a1158 2
    for (i = 0; i < *nsub; i++) {
      for (j = 0; j < *nsub; j++, dstp++) {
d1160 1
a1160 1
          k = (axes[i]-1)*naxis + (axes[j]-1);
d1174 1
a1174 1
    for (i = 0; i < *nsub; i++, dstp++) {
d1176 1
a1176 1
        k = axes[i] - 1;
d1189 1
a1189 1
  for (i = 0; i < *nsub; i++) {
d1191 1
a1191 1
      k = axes[i] - 1;
d1272 1
a1272 1
  for (itab = 0; itab < wcssrc->ntab; itab++) {
d1274 2
a1275 2
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];
d1296 4
a1299 4
  tab = wcsdst->tab;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];
d1307 18
d1333 2
a1334 1
  for (m = 0; m < 2; m++) {
d1347 1
a1347 1
      for (j = 0; j < *nsub; j++) {
d1349 1
a1349 1
          k = axes[j] - 1;
d1356 3
a1358 3
      ndp = 0;
      dpdst = disdst->dp;
      for (j = 0; j < *nsub; j++) {
d1362 2
a1363 1
        for (jhat = 0; jhat < 32; jhat++) {
d1367 3
a1369 3
        Nhat = 0;
        dpsrc = dissrc->dp;
        for (idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
d1372 1
d1379 1
d1385 1
a1385 1
        for (jhat = 0; jhat < Nhat; jhat++) {
d1393 1
a1393 1
        for (idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
d1396 1
d1406 1
d1415 1
a1415 1
            for (jhat = 0; jhat < Nhat; jhat++) {
d1449 1
a1449 3
    free(wcsdst->m_tab);
    wcsdst->tab   = 0x0;
    wcsdst->m_tab = 0x0;
a1464 3
  int i, j, naxis, naxis2;
  double diff;
  int tab_equal;
d1477 2
a1478 2
  naxis = wcs1->naxis;
  naxis2 = wcs1->naxis*wcs1->naxis;
d1483 2
a1484 2
    for (i = 0; i < naxis; ++i) {
      diff = wcs1->crpix[i] - wcs2->crpix[i];
d1510 2
a1511 1
  for (i = 0; i < wcs1->npv; ++i) {
d1528 2
a1529 1
  for (i = 0; i < wcs1->nps; ++i) {
d1622 2
a1623 1
  for (i = 0; i < wcs1->ntab; ++i) {
a2859 4
  const char *alt = "";
  char ctypei[16], pcode[4], requir[16], scode[4], specsys[9];
  int i, j, m, naxis, *ndx = 0x0, type;

d2864 1
d2872 1
d2876 1
a2876 1
  naxis = wcs->naxis;
d2882 2
a2883 1
  for (i = 0; i < naxis; i++) {
d2887 1
d2897 1
a2897 1
      for (j = 7; j > 0; j--) {
d2919 1
a2919 1
      for (j = 3; j >= 0; j--) {
d2926 1
d2934 1
a2934 1
      // Identify Stokes, celestial and spectral types.
d2975 4
d2986 1
d3005 1
d3108 2
a3109 2
  for (j = 0; j < wcs->ntab; j++) {
    for (m = 0; m < wcs->tab[j].M; m++) {
d3111 1
a3111 1
      i = wcs->tab[j].map[m];
d3113 1
a3113 1
      type = (wcs->types[i] / 100) % 10;
d3127 24
a3155 5
  char ctype[9], units[16];
  int  i, j, naxis;
  double scale, offset, power;
  struct wcserr *uniterr = 0x0, **err;

d3157 1
a3157 1
  err = &(wcs->err);
d3159 2
a3160 2
  naxis = wcs->naxis;
  for (i = 0; i < naxis; i++) {
d3165 1
d3189 2
d3206 1
a3206 1
        for (j = 0; j < naxis; j++) {
a3236 8
  int    bits, face, i, iso_x, iso_y, istat, *istatp, itab, k, m, nx, ny,
        *statp, status, type;
  double crvali, offset;
  register double *img, *wrl;
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  struct wcserr **err;

d3239 1
a3239 1
  err = &(wcs->err);
d3241 1
d3259 1
d3269 3
a3271 1
  for (i = 0; i < wcs->naxis; i++) {
d3273 1
a3273 1
    type = (wcs->types[i] / 100) % 10;
d3275 1
d3280 2
a3281 2
      crvali = wcs->crval[i];
      for (k = 0; k < ncoord; k++) {
d3291 1
d3300 4
a3303 4
        statp = stat;
        bits = (1 << i) | (1 << wcs->lat);
        for (k = 0; k < ncoord; k++, statp++) {
          face = (int)(*(img+wcs->cubeface) + 0.5);
d3340 3
a3342 3
      nx = ncoord;
      ny = 0;

d3352 1
d3374 1
a3374 1
        bits = (1 << i) | (1 << wcs->lat);
d3380 2
a3381 1
      nx = ncoord;
d3386 1
a3386 1
      istat = 0;
d3423 2
a3424 2
  for (itab = 0; itab < wcs->ntab; itab++) {
    istat = tabx2s(wcs->tab + itab, ncoord, nelem, imgcrd, world, istatp);
d3433 2
a3434 2
        bits = 0;
        for (m = 0; m < wcs->tab[itab].M; m++) {
d3444 1
a3444 1
  for (i = wcs->naxis; i < nelem; i++) {
a3469 10
  int    bits, i, isolat, isolng, isospec, istat, *istatp, itab, k, m, nlat,
         nlng, nwrld, status, type;
  double crvali, offset;
  register const double *wrl;
  register double *img;
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  struct wcserr **err;


d3472 1
a3472 1
  err = &(wcs->err);
d3474 1
d3486 1
d3497 3
a3499 1
  for (i = 0; i < wcs->naxis; i++) {
d3501 1
a3501 1
    type = (wcs->types[i] / 100) % 10;
d3505 4
a3508 4
      wrl = world  + i;
      img = imgcrd + i;
      crvali = wcs->crval[i];
      for (k = 0; k < ncoord; k++) {
d3516 3
a3518 2
      nlng = ncoord;
      nlat = 0;
d3529 1
d3551 1
a3551 1
        bits = (1 << i) | (1 << wcs->lat);
d3558 1
d3566 2
a3567 2
        img = imgcrd;
        for (k = 0; k < ncoord; k++) {
d3593 2
a3594 1
      nwrld = ncoord;
d3599 1
a3599 1
      istat = 0;
d3636 2
a3637 2
  for (itab = 0; itab < wcs->ntab; itab++) {
    istat = tabs2x(wcs->tab + itab, ncoord, nelem, world, imgcrd, istatp);
d3643 2
a3644 2
        bits = 0;
        for (m = 0; m < wcs->tab[itab].M; m++) {
d3657 1
a3657 1
  for (i = wcs->naxis; i < nelem; i++) {
d3664 1
a3693 1
  int    crossed, istep, iter, j, k, nstep, retry, stat[1], status;
a3695 11
  double *worldlat, *worldlng;
  double lambda, span[2], step;
  double pixmix;
  double dlng, lng, lng0, lng0m, lng1, lng1m;
  double dlat, lat, lat0, lat0m, lat1, lat1m;
  double d, d0, d0m, d1, d1m, dx = 0.0;
  double dabs, dmin, lmin;
  double dphi, phi0, phi1;
  struct celprm *wcscel = &(wcs->cel);
  struct wcsprm wcs0;
  struct wcserr **err;
d3699 1
a3699 1
  err = &(wcs->err);
d3701 1
d3711 2
a3712 2
  worldlng = world + wcs->lng;
  worldlat = world + wcs->lat;
d3716 1
d3727 1
a3727 1
  step = fabs(vstep);
d3734 1
a3734 1
  nstep = viter;
d3742 1
a3742 1
  pixmix = pixcrd[mixpix];
d3745 1
a3745 1
  for (istep = 0; istep <= nstep; istep++) {
d3753 1
a3753 1
      lat0 = span[0];
d3755 1
d3763 1
a3763 1
      d0 = pixcrd[mixpix] - pixmix;
d3765 1
a3765 1
      dabs = fabs(d0);
d3768 1
a3768 1
      lat1 = span[1];
d3777 1
a3777 1
      d1 = pixcrd[mixpix] - pixmix;
d3782 2
a3783 2
      lmin = lat1;
      dmin = dabs;
d3786 2
d3796 1
a3796 1
      for (retry = 0; retry < 4; retry++) {
d3835 1
a3835 1
          for (iter = 0; iter < niter; iter++) {
d3837 1
a3837 1
            lambda = d0/(d0-d1);
d3844 2
a3845 2
            dlat = lat1 - lat0;
            lat = lat0 + lambda*dlat;
d3856 1
a3856 1
            d = pixcrd[mixpix] - pixmix;
d3894 1
a3894 1
          lat = lmin;
d3910 1
a3910 1
          d  = dmin;
d3922 2
a3923 2
          for (iter = 0; iter < niter; iter++) {
            lat0m = (lat0 + lat)/2.0;
d3932 1
a3932 1
            d0m = fabs(pixcrd[mixpix] - pixmix);
d3936 1
a3936 1
            lat1m = (lat1 + lat)/2.0;
d3945 1
a3945 1
            d1m = fabs(pixcrd[mixpix] - pixmix);
d3973 1
a3973 1
      lng0 = span[0];
d3975 1
d3983 1
a3983 1
      d0 = pixcrd[mixpix] - pixmix;
d3985 1
a3985 1
      dabs = fabs(d0);
d3988 1
a3988 1
      lng1 = span[1];
d3997 1
a3997 1
      d1 = pixcrd[mixpix] - pixmix;
d4001 2
a4002 2
      lmin = lng1;
      dmin = dabs;
d4005 2
d4015 1
a4015 1
      for (retry = 0; retry < 4; retry++) {
d4054 1
a4054 1
          for (iter = 0; iter < niter; iter++) {
d4056 1
a4056 1
            lambda = d0/(d0-d1);
d4063 2
a4064 2
            dlng = lng1 - lng0;
            lng = lng0 + lambda*dlng;
d4075 1
a4075 1
            d = pixcrd[mixpix] - pixmix;
d4113 1
a4113 1
          lng = lmin;
d4129 1
a4129 1
          d  = dmin;
d4141 2
a4142 2
          for (iter = 0; iter < niter; iter++) {
            lng0m = (lng0 + lng)/2.0;
d4151 1
a4151 1
            d0m = fabs(pixcrd[mixpix] - pixmix);
d4155 1
a4155 1
            lng1m = (lng1 + lng)/2.0;
d4164 1
a4164 1
            d1m = fabs(pixcrd[mixpix] - pixmix);
d4192 1
a4192 1
  wcs0 = *wcs;
d4201 1
a4201 1
  for (j = 1; j <= 2; j++) {
d4205 2
d4230 1
d4240 1
a4240 1
    d0 = pixcrd[mixpix] - pixmix;
d4251 4
a4254 3
    phi0 = -180.0;
    for (k = -179; k <= 180; k++) {
      phi1 = (double) k;
d4268 1
a4268 1
      dabs = fabs(d1);
d4283 1
a4283 1
    for (iter = 1; iter <= niter; iter++) {
d4285 1
a4285 1
      lambda = d0/(d0-d1);
d4292 1
a4292 1
      dphi = phi1 - phi0;
d4305 2
a4306 2
      d = pixcrd[mixpix] - pixmix;
      dabs = fabs(d);
@


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


7.7.1.2
log
@Converted the remaining functions to C99-style intermingled variable
declarations, namely wcsinit(), wcsauxi(), wcssub(), wcscompare(),
wcs_units(), wcsp2s(), wcss2p(), and wcsmix().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.7.1.1 2021/07/12 06:38:27 mcalabre Exp mcalabre $
d155 3
a157 1
  int status;
d170 1
a170 1
  struct wcserr **err = &(wcs->err);
d551 1
a551 1
  for (int i = 0; i < naxis; i++) {
d557 1
a557 1
  for (int i = 0; i < naxis; i++) {
d573 1
a573 1
  for (int k = 0; k < wcs->npvmax; k++) {
d580 1
a580 1
  for (int k = 0; k < wcs->npsmax; k++) {
d587 3
a589 3
  double *cd = wcs->cd;
  for (int i = 0; i < naxis; i++) {
    for (int j = 0; j < naxis; j++) {
d593 1
a593 1
  for (int i = 0; i < naxis; i++) {
d604 1
a604 1
  for (int i = 0; i < naxis; i++) {
d694 3
d699 1
a699 1
  struct wcserr **err = &(wcs->err);
d716 1
a716 1
  struct auxprm *aux = wcs->aux;
d739 10
a748 1
  int  status;
d752 1
a752 1
  struct wcserr **err = &(wcsdst->err);
a754 1
  int naxis;
a759 1
  int dummy;
d768 1
a768 2
  int *itmp;
  int  ntmp = (*nsub <= naxis) ? naxis : *nsub;
a772 1
  int dealloc;
d780 1
a780 1
    for (int i = 0; i < naxis; i++) {
d790 3
a792 3
  int msub = 0;
  for (int j = 0; j < *nsub; j++) {
    int axis = axes[j];
d796 1
a796 1
      int k = abs(axis) & 0xFF;
d798 5
a802 5
      int longitude = k & WCSSUB_LONGITUDE;
      int latitude  = k & WCSSUB_LATITUDE;
      int cubeface  = k & WCSSUB_CUBEFACE;
      int spectral  = k & WCSSUB_SPECTRAL;
      int stokes    = k & WCSSUB_STOKES;
a803 1
      int other;
d812 1
a812 2
      for (int i = 0; i < naxis; i++) {
        char ctypei[16];
d817 1
a817 1
        char *c = ctypei + 8;
a875 1
        int k;
a885 1
      int k;
d909 1
a909 1
  for (int i = 0; i < *nsub; i++) {
d919 2
a920 2
  int *map = itmp;
  for (int i = 0; i < naxis; i++) {
d924 1
a924 1
  for (int i = 0; i < *nsub; i++) {
d933 3
a935 4
  double *dstp;
  const double *srcp = wcssrc->pc;
  for (int i = 0; i < naxis; i++) {
    for (int j = 0; j < naxis; j++) {
d947 2
a948 3
  int ndpmax = 0;
  for (int m = 0; m < 2; m++) {
    struct disprm *dissrc;
d955 1
a955 1
    int ndp = 0;
d957 1
a957 1
      for (int j = 0; j < naxis; j++) {
d961 1
a961 2
        int axmap[32];
        for (int jhat = 0; jhat < 32; jhat++) {
d965 3
a967 3
        int Nhat = 0;
        struct dpkey *dpsrc = dissrc->dp;
        for (int idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
a970 1
          char *fp;
a978 1
            int jhat;
d991 1
a991 1
        for (int jhat = 0; jhat < Nhat; jhat++) {
d1013 3
a1015 3
  int npvmax = 0;
  for (int m = 0; m < wcssrc->npv; m++) {
    int i = wcssrc->pv[m].i;
d1022 3
a1024 3
  int npsmax = 0;
  for (int m = 0; m < wcssrc->nps; m++) {
    int i = wcssrc->ps[m].i;
d1033 1
a1033 2
  for (int m = 0; m < 2; m++) {
    struct disprm *dissrc, *disdst;
d1061 1
a1061 1
  for (int j = 0; j < *nsub; j++, dstp++) {
d1063 1
a1063 1
      int k = axes[j] - 1;
d1070 2
a1071 2
  for (int i = 0; i < *nsub; i++) {
    for (int j = 0; j < *nsub; j++, dstp++) {
d1073 1
a1073 1
        int k = (axes[i]-1)*naxis + (axes[j]-1);
d1081 1
a1081 1
  for (int i = 0; i < *nsub; i++, dstp++) {
d1083 1
a1083 1
      int k = axes[i] - 1;
d1091 1
a1091 1
  for (int i = 0; i < *nsub; i++, dstp++) {
d1093 1
a1093 1
      int k = axes[i] - 1;
d1099 1
a1099 1
  for (int i = 0; i < *nsub; i++) {
d1101 1
a1101 1
      int k = axes[i] - 1;
d1114 3
a1116 3
  int npv = 0;
  for (int m = 0; m < wcssrc->npv; m++) {
    int i = wcssrc->pv[m].i;
d1130 3
a1132 3
  int nps = 0;
  for (int m = 0; m < wcssrc->nps; m++) {
    int i = wcssrc->ps[m].i;
d1145 2
a1146 2
    for (int i = 0; i < *nsub; i++) {
      for (int j = 0; j < *nsub; j++, dstp++) {
d1148 1
a1148 1
          int k = (axes[i]-1)*naxis + (axes[j]-1);
d1162 1
a1162 1
    for (int i = 0; i < *nsub; i++, dstp++) {
d1164 1
a1164 1
        int k = axes[i] - 1;
d1177 1
a1177 1
  for (int i = 0; i < *nsub; i++) {
d1179 1
a1179 1
      int k = axes[i] - 1;
d1260 1
a1260 1
  for (int itab = 0; itab < wcssrc->ntab; itab++) {
d1262 2
a1263 2
    for (int m = 0; m < wcssrc->tab[itab].M; m++) {
      int i = wcssrc->tab[itab].map[m];
d1284 4
a1287 4
  struct tabprm *tab = wcsdst->tab;
  for (int itab = 0; itab < wcssrc->ntab; itab++) {
    for (int m = 0; m < wcssrc->tab[itab].M; m++) {
      int i = wcssrc->tab[itab].map[m];
d1303 1
a1303 2
  for (int m = 0; m < 2; m++) {
    struct disprm *dissrc, *disdst;
d1316 1
a1316 1
      for (int j = 0; j < *nsub; j++) {
d1318 1
a1318 1
          int k = axes[j] - 1;
d1325 3
a1327 3
      int ndp = 0;
      struct dpkey *dpdst = disdst->dp;
      for (int j = 0; j < *nsub; j++) {
d1331 1
a1331 2
        int axmap[32];
        for (int jhat = 0; jhat < 32; jhat++) {
d1335 3
a1337 3
        int Nhat = 0;
        struct dpkey *dpsrc = dissrc->dp;
        for (int idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
a1339 1
          char *fp;
a1345 1
            int jhat;
d1351 1
a1351 1
        for (int jhat = 0; jhat < Nhat; jhat++) {
d1359 1
a1359 1
        for (int idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
a1361 1
          char *fp;
a1370 1
          char ctmp[16];
d1379 1
a1379 1
            for (int jhat = 0; jhat < Nhat; jhat++) {
d1431 3
d1446 2
a1447 2
  int naxis = wcs1->naxis;
  int naxis2 = wcs1->naxis*wcs1->naxis;
d1452 2
a1453 2
    for (int i = 0; i < naxis; ++i) {
      double diff = wcs1->crpix[i] - wcs2->crpix[i];
d1479 1
a1479 2
  for (int i = 0; i < wcs1->npv; ++i) {
    int j;
d1496 1
a1496 2
  for (int i = 0; i < wcs1->nps; ++i) {
    int j;
d1589 1
a1589 2
  for (int i = 0; i < wcs1->ntab; ++i) {
    int tab_equal;
d2826 3
a2828 1
  int i, j, m;
a2833 1
  char pcode[4], requir[16];
a2840 1
  const char *alt = "";
d2844 1
a2844 1
  int naxis = wcs->naxis;
d2850 1
a2850 2
  int *ndx = 0x0;
  for (int i = 0; i < naxis; i++) {
a2853 1
    char ctypei[16];
d2863 1
a2863 1
      for (int j = 7; j > 0; j--) {
d2885 1
a2885 1
      for (int j = 3; j >= 0; j--) {
a2891 1
    char specsys[9];
a2946 1
    char scode[4];
a2964 1
    int j;
d3067 2
a3068 2
  for (int j = 0; j < wcs->ntab; j++) {
    for (int m = 0; m < wcs->tab[j].M; m++) {
d3070 1
a3070 1
      int i = wcs->tab[j].map[m];
d3072 1
a3072 1
      int type = (wcs->types[i] / 100) % 10;
d3091 5
d3097 1
a3097 1
  struct wcserr **err = &(wcs->err);
d3099 2
a3100 2
  int naxis = wcs->naxis;
  for (int i = 0; i < naxis; i++) {
a3104 1
    char ctype[9], units[16];
a3127 2
      double scale, offset, power;
      struct wcserr *uniterr;
d3143 1
a3143 1
        for (int j = 0; j < naxis; j++) {
d3174 8
d3184 1
a3184 1
  struct wcserr **err = &(wcs->err);
a3185 1
  int status;
a3202 1
  int *istatp;
d3212 1
a3212 3
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  for (int i = 0; i < wcs->naxis; i++) {
d3214 1
a3214 1
    int type = (wcs->types[i] / 100) % 10;
a3215 1
    register double *img, *wrl;
d3220 2
a3221 2
      double crvali = wcs->crval[i];
      for (int k = 0; k < ncoord; k++) {
a3230 1
        double offset;
d3239 4
a3242 4
        int *statp = stat;
        int bits = (1 << i) | (1 << wcs->lat);
        for (int k = 0; k < ncoord; k++, statp++) {
          int face = (int)(*(img+wcs->cubeface) + 0.5);
d3279 3
a3281 3
      int iso_x, iso_y;
      int nx = ncoord;
      int ny = 0;
a3290 1
      int istat;
d3312 1
a3312 1
        int bits = (1 << i) | (1 << wcs->lat);
d3318 1
a3318 2
      int iso_x;
      int nx = ncoord;
d3323 1
a3323 1
      int istat = 0;
d3360 2
a3361 2
  for (int itab = 0; itab < wcs->ntab; itab++) {
    int istat = tabx2s(wcs->tab + itab, ncoord, nelem, imgcrd, world, istatp);
d3370 2
a3371 2
        int bits = 0;
        for (int m = 0; m < wcs->tab[itab].M; m++) {
d3381 1
a3381 1
  for (int i = wcs->naxis; i < nelem; i++) {
d3407 10
d3419 1
a3419 1
  struct wcserr **err = &(wcs->err);
a3420 1
  int status;
a3431 1
  int *istatp;
d3442 1
a3442 3
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  for (int i = 0; i < wcs->naxis; i++) {
d3444 1
a3444 1
    int type = (wcs->types[i] / 100) % 10;
d3448 4
a3451 4
      register const double *wrl = world  + i;
      register double *img = imgcrd + i;
      double crvali = wcs->crval[i];
      for (int k = 0; k < ncoord; k++) {
d3459 2
a3460 3
      int isolng, isolat;
      int nlng = ncoord;
      int nlat = 0;
a3470 1
      int istat;
d3492 1
a3492 1
        int bits = (1 << i) | (1 << wcs->lat);
a3498 1
        double offset;
d3506 2
a3507 2
        register double *img = imgcrd;
        for (int k = 0; k < ncoord; k++) {
d3533 1
a3533 2
      int isospec;
      int nwrld = ncoord;
d3538 1
a3538 1
      int istat = 0;
d3575 2
a3576 2
  for (int itab = 0; itab < wcs->ntab; itab++) {
    int istat = tabs2x(wcs->tab + itab, ncoord, nelem, world, imgcrd, istatp);
d3582 2
a3583 2
        int bits = 0;
        for (int m = 0; m < wcs->tab[itab].M; m++) {
d3596 1
a3596 1
  for (int i = wcs->naxis; i < nelem; i++) {
a3602 1
  int istat;
d3632 1
d3635 11
d3649 1
a3649 1
  struct wcserr **err = &(wcs->err);
a3650 1
  int status;
d3660 2
a3661 2
  double *worldlng = world + wcs->lng;
  double *worldlat = world + wcs->lat;
a3664 1
  double span[2];
d3675 1
a3675 1
  double step = fabs(vstep);
d3682 1
a3682 1
  int nstep = viter;
d3690 1
a3690 1
  double pixmix = pixcrd[mixpix];
d3693 1
a3693 1
  for (int istep = 0; istep <= nstep; istep++) {
d3701 1
a3701 1
      double lat0 = span[0];
a3702 1
      int stat[1];
d3710 1
a3710 1
      double d0 = pixcrd[mixpix] - pixmix;
d3712 1
a3712 1
      double dabs = fabs(d0);
d3715 1
a3715 1
      double lat1 = span[1];
d3724 1
a3724 1
      double d1 = pixcrd[mixpix] - pixmix;
d3729 2
a3730 2
      double lmin = lat1;
      double dmin = dabs;
a3732 2
      int crossed;
      double dx = 0.0;
d3741 1
a3741 1
      for (int retry = 0; retry < 4; retry++) {
d3780 1
a3780 1
          for (int iter = 0; iter < niter; iter++) {
d3782 1
a3782 1
            double lambda = d0/(d0-d1);
d3789 2
a3790 2
            double dlat = lat1 - lat0;
            double lat = lat0 + lambda*dlat;
d3801 1
a3801 1
            double d = pixcrd[mixpix] - pixmix;
d3839 1
a3839 1
          double lat = lmin;
d3855 1
a3855 1
          double d  = dmin;
d3867 2
a3868 2
          for (int iter = 0; iter < niter; iter++) {
            double lat0m = (lat0 + lat)/2.0;
d3877 1
a3877 1
            double d0m = fabs(pixcrd[mixpix] - pixmix);
d3881 1
a3881 1
            double lat1m = (lat1 + lat)/2.0;
d3890 1
a3890 1
            double d1m = fabs(pixcrd[mixpix] - pixmix);
d3918 1
a3918 1
      double lng0 = span[0];
a3919 1
      int stat[1];
d3927 1
a3927 1
      double d0 = pixcrd[mixpix] - pixmix;
d3929 1
a3929 1
      double dabs = fabs(d0);
d3932 1
a3932 1
      double lng1 = span[1];
d3941 1
a3941 1
      double d1 = pixcrd[mixpix] - pixmix;
d3945 2
a3946 2
      double lmin = lng1;
      double dmin = dabs;
a3948 2
      int crossed;
      double dx = 0.0;
d3957 1
a3957 1
      for (int retry = 0; retry < 4; retry++) {
d3996 1
a3996 1
          for (int iter = 0; iter < niter; iter++) {
d3998 1
a3998 1
            double lambda = d0/(d0-d1);
d4005 2
a4006 2
            double dlng = lng1 - lng0;
            double lng = lng0 + lambda*dlng;
d4017 1
a4017 1
            double d = pixcrd[mixpix] - pixmix;
d4055 1
a4055 1
          double lng = lmin;
d4071 1
a4071 1
          double d  = dmin;
d4083 2
a4084 2
          for (int iter = 0; iter < niter; iter++) {
            double lng0m = (lng0 + lng)/2.0;
d4093 1
a4093 1
            double d0m = fabs(pixcrd[mixpix] - pixmix);
d4097 1
a4097 1
            double lng1m = (lng1 + lng)/2.0;
d4106 1
a4106 1
            double d1m = fabs(pixcrd[mixpix] - pixmix);
d4134 1
a4134 1
  struct wcsprm wcs0 = *wcs;
d4143 1
a4143 1
  for (int j = 1; j <= 2; j++) {
a4146 2
    struct celprm *wcscel = &(wcs->cel);
    double lng, lat;
a4169 1
    int stat[1];
d4179 1
a4179 1
    double d0 = pixcrd[mixpix] - pixmix;
d4190 3
a4192 4
    double phi0 = -180.0, phi1;
    double d1;
    for (int k = -179; k <= 180; k++) {
      phi1 = (double)k;
d4206 1
a4206 1
      double dabs = fabs(d1);
d4221 1
a4221 1
    for (int iter = 1; iter <= niter; iter++) {
d4223 1
a4223 1
      double lambda = d0/(d0-d1);
d4230 1
a4230 1
      double dphi = phi1 - phi0;
d4243 2
a4244 2
      double d = pixcrd[mixpix] - pixmix;
      double dabs = fabs(d);
@


7.7.1.3
log
@Bug fix in wcssub() for tables that change axis number, thus requiring
tabprm::map to be updated.  Also check that all axes of a multi-dimensional
table are extracted together.  Also in wcssub(), subimage extraction by
coordinate type now recognises time axes via WCSSUB_TIME, and the error
messages for non-separable coordinate systems are more informative.  In
wcs_types(), identify time coordinate axes in wcsprm::types using a new
helper function, time_types().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.7.1.2 2022/03/16 08:14:29 mcalabre Exp mcalabre $
a126 1
static int time_type(const char *);
a792 1
      int time      = k & WCSSUB_TIME;
a800 1
        time      = !time;
a862 5
        } else if (strcmp(ctypei, "TIME") == 0 || time_type(ctypei)) {
          if (!time) {
            continue;
          }

d934 1
a934 2
        status = wcserr_set(WCSERR_SET(WCSERR_NON_SEPARABLE),
          "Non-zero off-diagonal matrix elements excluded from the subimage");
a939 2
  // Tabular coordinates, if any, will be checked below.

d1000 1
a1000 2
            status = wcserr_set(WCSERR_SET(WCSERR_NON_SEPARABLE),
              "Distortion depends on an axis excluded from the subimage.");
a1294 18
        // Translate axis numbers in tab->map[].
        for (int m = 0; m < wcssrc->tab[itab].M; m++) {
          // Table axis mapping, followed by...
          int i = wcssrc->tab[itab].map[m];

          // ...subimaging axis mapping.
          int j = map[i] - 1;
          if (j < 0) {
            // In general, multi-dimensional tables (i.e. with M > 1) are not
            // separable, so if one axis is selected then all must be.
            status = wcserr_set(WCSERR_SET(WCSERR_NON_SEPARABLE),
              "Table with M>1 depends on axis excluded from the subimage");
            goto cleanup;
          }

          tab->map[m] = j;
        }

d2908 1
a2908 1
      // Identify Stokes, celestial, spectral, and time types.
a2948 4

      } else if (strcmp(ctypei, "TIME") == 0 || time_type(ctypei)) {
        // Time axis.
        wcs->types[i] += 4000;
a3092 24
}

// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :

int time_type(const char *ctype)

{
  // Is it a recognised time system as listed in Table 2 of WCS Paper VII?
  if (strcmp(ctype, "UTC")) return 1;
  if (strcmp(ctype, "TAI")) return 1;
  if (strcmp(ctype, "IAT")) return 1;
  if (strcmp(ctype, "TT"))  return 1;
  if (strcmp(ctype, "TDB")) return 1;
  if (strcmp(ctype, "TDT")) return 1;
  if (strcmp(ctype, "GPS")) return 1;
  if (strcmp(ctype, "TCB")) return 1;
  if (strcmp(ctype, "TCG")) return 1;
  if (strcmp(ctype, "GMT")) return 1;
  if (strcmp(ctype, "UT1")) return 1;
  if (strcmp(ctype, "UT"))  return 1;
  if (strcmp(ctype, "ET"))  return 1;
  if (strcmp(ctype, "LOCAL")) return 1;

  return 0;
@


7.7.1.4
log
@In wcs_types(), removed declaration of unused variables.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.7.1.3 2022/03/22 05:15:25 mcalabre Exp mcalabre $
d2861 2
@


7.7.1.5
log
@In wcssub(), on cleanup free tabprm memory using tabfree().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.7.1.4 2022/03/22 06:12:49 mcalabre Exp mcalabre $
d1449 3
a1451 1
    tabfree(wcsdst->m_tab);
@


7.7.1.6
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2022, Mark Calabretta
d22 1
a22 1
  $Id: wcs.c,v 7.7.1.5 2022/03/25 05:39:35 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: wcs.c,v 7.5.1.5 2021/04/13 09:29:31 mcalabre Exp mcalabre $
d1784 1
a1784 1
    if (wcsutil_all_sval(wcs->naxis, "", wcs->cname)) {
@


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


7.6.1.2
log
@In wcstrim(), quelled a warning from gcc 11.1.0: "pointers to arrays with
with different qualifiers are incompatible in ISO C [-Wpedantic]".
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.6.1.1 2021/04/13 13:00:35 mcalabre Exp mcalabre $
d1784 1
a1784 1
    if (wcsutil_all_sval(wcs->naxis, "", (const char (*)[72])wcs->cname)) {
@


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: wcs.c,v 7.4.1.2 2021/02/22 07:23:26 mcalabre Exp mcalabre $
d68 2
a69 1
  "Non-separable subimage coordinate system"};
d682 1
a682 1
  return 0;
d723 1
a723 1
  return 0;
d1142 13
a1154 11
  srcp = wcssrc->cd;
  dstp = wcsdst->cd;
  for (i = 0; i < *nsub; i++) {
    for (j = 0; j < *nsub; j++, dstp++) {
      if (axes[i] > 0 && axes[j] > 0) {
        k = (axes[i]-1)*naxis + (axes[j]-1);
        *dstp = *(srcp+k);
      } else if (i == j && wcssrc->altlin & 2) {
        // A new axis is being created where CDi_ja was present in the input
        // header, so override the default value of 0 set by wcsinit().
        *dstp = 1.0;
d1159 8
a1166 6
  srcp = wcssrc->crota;
  dstp = wcsdst->crota;
  for (i = 0; i < *nsub; i++, dstp++) {
    if (axes[i] > 0) {
      k = axes[i] - 1;
      *dstp = *(srcp+k);
d1180 6
a1185 6
      wcsdst->colax[i] = wcssrc->colax[k];
      strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
      wcsdst->crder[i] = wcssrc->crder[k];
      wcsdst->csyer[i] = wcssrc->csyer[k];
      wcsdst->czphs[i] = wcssrc->czphs[k];
      wcsdst->cperi[i] = wcssrc->cperi[k];
d1459 1
a1459 1
    if (!wcsutil_Eq(naxis, tol, wcs1->crpix, wcs2->crpix)) {
d1464 3
a1466 3
  if (!wcsutil_Eq(naxis2, tol, wcs1->pc, wcs2->pc) ||
      !wcsutil_Eq(naxis, tol, wcs1->cdelt, wcs2->cdelt) ||
      !wcsutil_Eq(naxis, tol, wcs1->crval, wcs2->crval) ||
d1469 4
a1472 4
      !wcsutil_Eq(1, tol, &wcs1->lonpole, &wcs2->lonpole) ||
      !wcsutil_Eq(1, tol, &wcs1->latpole, &wcs2->latpole) ||
      !wcsutil_Eq(1, tol, &wcs1->restfrq, &wcs2->restfrq) ||
      !wcsutil_Eq(1, tol, &wcs1->restwav, &wcs2->restwav) ||
d1483 1
a1483 1
        if (!wcsutil_Eq(1, tol, &wcs1->pv[i].value, &wcs2->pv[j].value)) {
d1513 2
a1514 2
    if (!wcsutil_Eq(naxis2, tol, wcs1->cd, wcs2->cd) ||
        !wcsutil_Eq(naxis, tol, wcs1->crota, wcs2->crota) ||
d1526 4
a1529 4
        !wcsutil_Eq(naxis, tol, wcs1->crder, wcs2->crder) ||
        !wcsutil_Eq(naxis, tol, wcs1->csyer, wcs2->csyer) ||
        !wcsutil_Eq(naxis, tol, wcs1->czphs, wcs2->czphs) ||
        !wcsutil_Eq(naxis, tol, wcs1->cperi, wcs2->cperi) ||
d1537 2
a1538 2
        !wcsutil_Eq(2, tol,  wcs1->mjdref,    wcs2->mjdref)   ||
        !wcsutil_Eq(1, tol, &wcs1->timeoffs, &wcs2->timeoffs) ||
d1543 15
a1557 15
        !wcsutil_Eq(1, tol, &wcs1->mjdobs,   &wcs2->mjdobs)   ||
        !wcsutil_Eq(1, tol, &wcs1->mjdbeg,   &wcs2->mjdbeg)   ||
        !wcsutil_Eq(1, tol, &wcs1->mjdavg,   &wcs2->mjdavg)   ||
        !wcsutil_Eq(1, tol, &wcs1->mjdend,   &wcs2->mjdend)   ||
        !wcsutil_Eq(1, tol, &wcs1->jepoch,   &wcs2->jepoch)   ||
        !wcsutil_Eq(1, tol, &wcs1->bepoch,   &wcs2->bepoch)   ||
        !wcsutil_Eq(1, tol, &wcs1->tstart,   &wcs2->tstart)   ||
        !wcsutil_Eq(1, tol, &wcs1->tstop,    &wcs2->tstop)    ||
        !wcsutil_Eq(1, tol, &wcs1->xposure,  &wcs2->xposure)  ||
        !wcsutil_Eq(1, tol, &wcs1->telapse,  &wcs2->telapse)  ||
        !wcsutil_Eq(1, tol, &wcs1->timsyer,  &wcs2->timsyer)  ||
        !wcsutil_Eq(1, tol, &wcs1->timrder,  &wcs2->timrder)  ||
        !wcsutil_Eq(1, tol, &wcs1->timedel,  &wcs2->timedel)  ||
        !wcsutil_Eq(1, tol, &wcs1->timepixr, &wcs2->timepixr) ||
        !wcsutil_Eq(6, tol,  wcs1->obsgeo,    wcs2->obsgeo)   ||
d1560 1
a1560 1
        !wcsutil_Eq(1, tol, &wcs1->equinox,  &wcs2->equinox)  ||
d1563 2
a1564 2
        !wcsutil_Eq(1, tol, &wcs1->velosys,  &wcs2->velosys)  ||
        !wcsutil_Eq(1, tol, &wcs1->zsource,  &wcs2->zsource)  ||
d1566 1
a1566 1
        !wcsutil_Eq(1, tol, &wcs1->velangl,  &wcs2->velangl)) {
d1572 5
a1576 5
      if (!wcsutil_Eq(1, tol, &wcs1->aux->rsun_ref, &wcs2->aux->rsun_ref) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->dsun_obs, &wcs2->aux->dsun_obs) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->crln_obs, &wcs2->aux->crln_obs) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->hgln_obs, &wcs2->aux->hgln_obs) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->hglt_obs, &wcs2->aux->hglt_obs)) {
a1606 2
  int j;

d1660 2
a1661 2
        for (j = 0; j < wcs->ntab; j++) {
          tabfree(wcs->m_tab + j);
d1713 241
a1953 1
  return 0;
d1956 1
a1979 3
  int i, j, k;
  struct wtbarr *wtbp;

d1984 1
a1984 1
    return 0;
d1991 1
a1991 1
  for (i = 0; i < wcs->naxis; i++) {
d1997 1
a1997 1
  k = 0;
d1999 1
a1999 1
  for (i = 0; i < wcs->naxis; i++) {
d2001 1
a2001 1
    for (j = 0; j < wcs->naxis; j++) {
d2010 1
a2010 1
  for (i = 0; i < wcs->naxis; i++) {
d2018 1
a2018 1
  for (i = 0; i < wcs->naxis; i++) {
d2025 1
a2025 1
  for (i = 0; i < wcs->naxis; i++) {
d2030 1
a2030 1
  for (i = 0; i < wcs->naxis; i++) {
d2048 3
a2050 3
  for (i = 0; i < wcs->npv; i++) {
    wcsprintf("             %3d%4d  %#- 11.5g\n", (wcs->pv[i]).i,
      (wcs->pv[i]).m, (wcs->pv[i]).value);
d2055 3
a2057 3
  for (i = 0; i < wcs->nps; i++) {
    wcsprintf("             %3d%4d  %s\n", (wcs->ps[i]).i,
      (wcs->ps[i]).m, (wcs->ps[i]).value);
d2064 1
a2064 1
    for (i = 0; i < wcs->naxis; i++) {
d2066 1
a2066 1
      for (j = 0; j < wcs->naxis; j++) {
d2076 1
a2076 1
    for (i = 0; i < wcs->naxis; i++) {
d2094 1
a2094 1
    for (i = 0; i < wcs->naxis; i++) {
d2102 1
a2102 1
    for (i = 0; i < wcs->naxis; i++) {
d2114 1
a2114 1
    for (i = 0; i < wcs->naxis; i++) {
d2127 1
a2127 1
    for (i = 0; i < wcs->naxis; i++) {
d2140 1
a2140 1
    for (i = 0; i < wcs->naxis; i++) {
d2153 1
a2153 1
    for (i = 0; i < wcs->naxis; i++) {
d2172 2
a2173 2
  for (i = 0; i < 2; i++) {
    if (undefined(wcs->mjdref[i])) {
d2176 1
a2176 1
      wcsprintf(" %15.9f", wcs->mjdref[i]);
d2204 2
a2205 2
  for (i = 0; i < 3; i++) {
    if (undefined(wcs->obsgeo[i])) {
d2208 1
a2208 1
      wcsprintf(" %15.6f", wcs->obsgeo[i]);
d2212 2
a2213 2
  for (i = 3; i < 6; i++) {
    if (undefined(wcs->obsgeo[i])) {
d2216 1
a2216 1
      wcsprintf(" %15.6f", wcs->obsgeo[i]);
d2252 1
a2252 1
  for (i = 0; i < wcs->naxis; i++) {
d2336 3
a2338 2
  if ((wtbp = wcs->wtb)) {
    for (j = 0; j < wcs->nwtb; j++, wtbp++) {
d2340 1
a2340 1
      wcsprintf("wtb[%d].*\n", j);
d2357 1
a2357 1
    for (j = 0; j < wcs->ntab; j++) {
d2359 2
a2360 2
      wcsprintf("tab[%d].*\n", j);
      tabprt(wcs->tab + j);
d2379 1
a2379 1
  return 0;
a2386 2
  int j;

d2394 2
a2395 2
      for (j = 0; j < wcs->ntab; j++) {
        wcserr_prt((wcs->tab + j)->err, prefix);
d2400 1
a2400 1
  return 0;
a2407 2
  int status;

d2411 1
d2417 1
a2417 1
  return 0;
a2426 13
  char   dpq[16], scode[4], stype[5];
  int    i, j, k, m, n, naxis, ndpmax, status;
  double lambda, rho;
  double *cd, *pc;
  struct disprm *dis;
  struct dpkey  *keyp;
  struct linprm *wcslin = &(wcs->lin);
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  struct spcprm *wcsspc = &(wcs->spc);
  struct wcserr **err;


d2428 1
a2428 1
  err = &(wcs->err);
d2431 1
d2441 1
a2441 1
  naxis = wcs->naxis;
d2450 1
d2460 1
d2466 1
d2471 1
a2471 1
      ndpmax = 6 + wcs->npv;
d2474 2
d2492 1
a2492 1
      keyp = dis->dp;
d2502 1
a2502 1
      for (k = 0; k < wcs->npv; k++) {
d2516 1
a2516 1
      for (k = 0; k < wcs->npv; k++) {
d2524 3
a2526 3
      n = 0;
      for (k = 0; k < wcs->npv; k++) {
        i = wcs->pv[k].i - 1;
d2558 1
a2558 1
    for (k = 0; k < wcs->npv; k++) {
d2564 2
a2565 2
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;
d2631 3
a2633 3
    for (k = 0; k < wcs->npv; k++) {
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;
d2657 2
d2673 3
a2675 3
    for (k = 0; k < wcs->npv; k++) {
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;
d2693 2
a2694 2
  for (j = 0; j < wcs->ntab; j++) {
    if ((status = tabset(wcs->tab + j))) {
d2701 1
a2701 1
  wcs->altlin &= 7;
d2703 1
a2703 1
    pc = wcs->pc;
d2705 1
a2705 1
    if (wcs->altlin & 2) {
d2707 3
a2709 3
      cd = wcs->cd;
      for (i = 0; i < naxis; i++) {
        for (j = 0; j < naxis; j++) {
d2717 1
d2719 1
a2719 1
        rho = wcs->crota[j];
d2725 1
a2725 1
        lambda = wcs->cdelt[j]/wcs->cdelt[i];
d2781 1
a2781 1
  for (i = 0; i < naxis; i++) {
d2813 1
a2813 1
  return 0;
a2828 1
  struct wcserr **err;
d2831 1
a2831 1
  err = &(wcs->err);
d3081 1
a3081 1
  return 0;
d3101 3
a3126 1
    wcsutil_null_fill(72, wcs->cunit[i]);
d3155 1
a3155 1
  return 0;
d3655 5
d3713 1
a3713 1
      if (dabs < tol) return 0;
d3727 1
a3727 1
      if (dabs < tol) return 0;
d3758 1
a3758 1
          if (dabs < tol) return 0;
d3803 1
a3803 1
            if (dabs < tol) return 0;
d3807 1
a3807 1
              if (dabs < tol2) return 0;
d3879 1
a3879 1
            if (d0m < tol) return 0;
d3892 1
a3892 1
            if (d1m < tol) return 0;
d3930 1
a3930 1
      if (dabs < tol) return 0;
d3944 1
a3944 1
      if (dabs < tol) return 0;
d3974 1
a3974 1
          if (dabs < tol) return 0;
d4019 1
a4019 1
            if (dabs < tol) return 0;
d4023 1
a4023 1
              if (dabs < tol2) return 0;
d4095 1
a4095 1
            if (d0m < tol) return 0;
d4108 1
a4108 1
            if (d1m < tol) return 0;
d4186 1
a4186 1
      return 0;
d4211 1
a4211 1
        return 0;
d4249 1
a4249 1
        return 0;
d4283 2
a4289 1
    int status;
d4295 1
a4295 1
      "Image does not have celestial axes.");
d4449 4
a4452 1
  return 0;
d4465 1
a4465 3
  int    j, status;
  double cdelt, crval;
  struct wcserr **err;
d4469 1
a4469 1
  err = &(wcs->err);
d4475 1
d4488 1
a4488 1
          "No spectral axis found.");
d4496 1
d4515 4
a4518 1
  return 0;
@


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


7.5.1.2
log
@In wcsmix(), check that the coordinate description does contain celestial
axes.  In wcsccs(), invoke wcsset() before returning.  In wcssptr(), converted
to C99-style intermingled variable declarations.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.5.1.1 2021/03/20 05:56:42 mcalabre Exp mcalabre $
a3418 5
  if (wcs->lng < 0 || wcs->lat < 0) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_SUBIMAGE),
      "Image does not have celestial axes");
  }

a4041 2
  int status;

d4047 1
d4053 1
a4053 1
      "Image does not have celestial axes");
a4206 3
  // Reset the struct.
  if ((status = wcsset(wcs))) return status;

d4220 3
a4222 1
  int status;
d4226 1
a4226 1
  struct wcserr **err = &(wcs->err);
a4231 1
  int j;
d4244 1
a4244 1
          "No spectral axis found");
a4251 1
  double cdelt, crval;
a4268 3

  // Reset the struct.
  if ((status = wcsset(wcs))) return status;
@


7.5.1.3
log
@In wcs_units(), ensure that trailing blanks are removed from all
wcsprm::cunit strings.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.5.1.2 2021/04/09 03:55:45 mcalabre Exp mcalabre $
a2866 3
    // Squeeze out trailing blanks.
    wcsutil_null_fill(72, wcs->cunit[i]);

d2890 1
@


7.5.1.4
log
@Converted to C99-style variable declarations in wcsfree(), wcsprt(),
wcsperr(), wcsbchk(), and wcsset().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.5.1.3 2021/04/09 15:19:41 mcalabre Exp mcalabre $
d1602 2
d1657 2
a1658 2
        for (int itab = 0; itab < wcs->ntab; itab++) {
          tabfree(wcs->m_tab + itab);
d1736 3
d1750 1
a1750 1
  for (int i = 0; i < wcs->naxis; i++) {
d1756 1
a1756 1
  int k = 0;
d1758 1
a1758 1
  for (int i = 0; i < wcs->naxis; i++) {
d1760 1
a1760 1
    for (int j = 0; j < wcs->naxis; j++) {
d1769 1
a1769 1
  for (int i = 0; i < wcs->naxis; i++) {
d1777 1
a1777 1
  for (int i = 0; i < wcs->naxis; i++) {
d1784 1
a1784 1
  for (int i = 0; i < wcs->naxis; i++) {
d1789 1
a1789 1
  for (int i = 0; i < wcs->naxis; i++) {
d1807 3
a1809 3
  for (int k = 0; k < wcs->npv; k++) {
    wcsprintf("             %3d%4d  %#- 11.5g\n", (wcs->pv[k]).i,
      (wcs->pv[k]).m, (wcs->pv[k]).value);
d1814 3
a1816 3
  for (int k = 0; k < wcs->nps; k++) {
    wcsprintf("             %3d%4d  %s\n", (wcs->ps[k]).i,
      (wcs->ps[k]).m, (wcs->ps[k]).value);
d1823 1
a1823 1
    for (int i = 0; i < wcs->naxis; i++) {
d1825 1
a1825 1
      for (int j = 0; j < wcs->naxis; j++) {
d1835 1
a1835 1
    for (int i = 0; i < wcs->naxis; i++) {
d1853 1
a1853 1
    for (int i = 0; i < wcs->naxis; i++) {
d1861 1
a1861 1
    for (int i = 0; i < wcs->naxis; i++) {
d1873 1
a1873 1
    for (int i = 0; i < wcs->naxis; i++) {
d1886 1
a1886 1
    for (int i = 0; i < wcs->naxis; i++) {
d1899 1
a1899 1
    for (int i = 0; i < wcs->naxis; i++) {
d1912 1
a1912 1
    for (int i = 0; i < wcs->naxis; i++) {
d1931 2
a1932 2
  for (int k = 0; k < 2; k++) {
    if (undefined(wcs->mjdref[k])) {
d1935 1
a1935 1
      wcsprintf(" %15.9f", wcs->mjdref[k]);
d1963 2
a1964 2
  for (int k = 0; k < 3; k++) {
    if (undefined(wcs->obsgeo[k])) {
d1967 1
a1967 1
      wcsprintf(" %15.6f", wcs->obsgeo[k]);
d1971 2
a1972 2
  for (int k = 3; k < 6; k++) {
    if (undefined(wcs->obsgeo[k])) {
d1975 1
a1975 1
      wcsprintf(" %15.6f", wcs->obsgeo[k]);
d2011 1
a2011 1
  for (int i = 0; i < wcs->naxis; i++) {
d2095 2
a2096 3
  struct wtbarr *wtbp = wcs->wtb;
  if (wtbp) {
    for (int iwtb = 0; iwtb < wcs->nwtb; iwtb++, wtbp++) {
d2098 1
a2098 1
      wcsprintf("wtb[%d].*\n", iwtb);
d2115 1
a2115 1
    for (int itab = 0; itab < wcs->ntab; itab++) {
d2117 2
a2118 2
      wcsprintf("tab[%d].*\n", itab);
      tabprt(wcs->tab + itab);
d2145 2
d2154 2
a2155 2
      for (int itab = 0; itab < wcs->ntab; itab++) {
        wcserr_prt((wcs->tab + itab)->err, prefix);
d2168 2
a2172 1
    int status;
d2188 13
d2202 1
a2202 1
  struct wcserr **err = &(wcs->err);
a2204 1
  int status;
d2214 1
a2214 1
  int naxis = wcs->naxis;
a2222 1
    struct celprm *wcscel = &(wcs->cel);
a2231 1
    struct prjprm *wcsprj = &(wcscel->prj);
a2236 1
      struct disprm *dis;
d2241 1
a2241 1
      int ndpmax = 6 + wcs->npv;
a2243 2
      char dpq[16];
      struct linprm *wcslin = &(wcs->lin);
d2260 1
a2260 1
      struct dpkey *keyp = dis->dp;
d2270 1
a2270 1
      for (int k = 0; k < wcs->npv; k++) {
d2284 1
a2284 1
      for (int k = 0; k < wcs->npv; k++) {
d2292 3
a2294 3
      int n = 0;
      for (int k = 0; k < wcs->npv; k++) {
        int i = wcs->pv[k].i - 1;
d2326 1
a2326 1
    for (int k = 0; k < wcs->npv; k++) {
d2332 2
a2333 2
      int i = wcs->pv[k].i - 1;
      int m = wcs->pv[k].m;
d2399 3
a2401 3
    for (int k = 0; k < wcs->npv; k++) {
      int i = wcs->pv[k].i - 1;
      int m = wcs->pv[k].m;
a2424 2
    char scode[4], stype[5];
    struct spcprm *wcsspc = &(wcs->spc);
d2439 3
a2441 3
    for (int k = 0; k < wcs->npv; k++) {
      int i = wcs->pv[k].i - 1;
      int m = wcs->pv[k].m;
d2459 2
a2460 2
  for (int itab = 0; itab < wcs->ntab; itab++) {
    if ((status = tabset(wcs->tab + itab))) {
d2467 1
a2467 1
  wcs->altlin &= 15;
d2469 1
a2469 1
    double *pc = wcs->pc;
d2471 1
a2471 1
    if ((wcs->altlin & 2) && !(wcs->altlin & 8)) {
d2473 3
a2475 3
      double *cd = wcs->cd;
      for (int i = 0; i < naxis; i++) {
        for (int j = 0; j < naxis; j++) {
a2482 1
      int i, j;
d2484 1
a2484 1
        double rho = wcs->crota[j];
d2490 1
a2490 1
        double lambda = wcs->cdelt[j]/wcs->cdelt[i];
d2546 1
a2546 1
  for (int i = 0; i < naxis; i++) {
d2594 1
d2597 1
a2597 1
  struct wcserr **err = &(wcs->err);
@


7.5.1.5
log
@Added new functions wcstrim(), wcssize(), and auxsize().  New error code
WCSERR_UNSET for wcstrim().  wcssub() must now account for the possibility
that some array pointers can now be NULL.  wcsutil_Eq() -> wcsutil_dblEq().
Use WCSERR_SUCCESS return code.
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.5.1.4 2021/04/10 14:22:30 mcalabre Exp mcalabre $
d68 1
a68 2
  "Non-separable subimage coordinate system",
  "wcsprm struct is unset, use wcsset()"};
d681 1
a681 1
  return WCSERR_SUCCESS;
d722 1
a722 1
  return WCSERR_SUCCESS;
d1141 11
a1151 13
  if (wcssrc->cd) {
    srcp = wcssrc->cd;
    dstp = wcsdst->cd;
    for (i = 0; i < *nsub; i++) {
      for (j = 0; j < *nsub; j++, dstp++) {
        if (axes[i] > 0 && axes[j] > 0) {
          k = (axes[i]-1)*naxis + (axes[j]-1);
          *dstp = *(srcp+k);
        } else if (i == j && wcssrc->altlin & 2) {
          // A new axis is being created where CDi_ja was present in the input
          // header, so override the default value of 0 set by wcsinit().
          *dstp = 1.0;
        }
d1156 6
a1161 8
  if (wcssrc->crota) {
    srcp = wcssrc->crota;
    dstp = wcsdst->crota;
    for (i = 0; i < *nsub; i++, dstp++) {
      if (axes[i] > 0) {
        k = axes[i] - 1;
        *dstp = *(srcp+k);
      }
d1175 6
a1180 6
      if (wcssrc->colax) wcsdst->colax[i] = wcssrc->colax[k];
      if (wcssrc->cname) strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
      if (wcssrc->crder) wcsdst->crder[i] = wcssrc->crder[k];
      if (wcssrc->csyer) wcsdst->csyer[i] = wcssrc->csyer[k];
      if (wcssrc->czphs) wcsdst->czphs[i] = wcssrc->czphs[k];
      if (wcssrc->cperi) wcsdst->cperi[i] = wcssrc->cperi[k];
d1454 1
a1454 1
    if (!wcsutil_dblEq(naxis, tol, wcs1->crpix, wcs2->crpix)) {
d1459 3
a1461 3
  if (!wcsutil_dblEq(naxis2, tol, wcs1->pc, wcs2->pc) ||
      !wcsutil_dblEq(naxis, tol, wcs1->cdelt, wcs2->cdelt) ||
      !wcsutil_dblEq(naxis, tol, wcs1->crval, wcs2->crval) ||
d1464 4
a1467 4
      !wcsutil_dblEq(1, tol, &wcs1->lonpole, &wcs2->lonpole) ||
      !wcsutil_dblEq(1, tol, &wcs1->latpole, &wcs2->latpole) ||
      !wcsutil_dblEq(1, tol, &wcs1->restfrq, &wcs2->restfrq) ||
      !wcsutil_dblEq(1, tol, &wcs1->restwav, &wcs2->restwav) ||
d1478 1
a1478 1
        if (!wcsutil_dblEq(1, tol, &wcs1->pv[i].value, &wcs2->pv[j].value)) {
d1508 2
a1509 2
    if (!wcsutil_dblEq(naxis2, tol, wcs1->cd, wcs2->cd) ||
        !wcsutil_dblEq(naxis, tol, wcs1->crota, wcs2->crota) ||
d1521 4
a1524 4
        !wcsutil_dblEq(naxis, tol, wcs1->crder, wcs2->crder) ||
        !wcsutil_dblEq(naxis, tol, wcs1->csyer, wcs2->csyer) ||
        !wcsutil_dblEq(naxis, tol, wcs1->czphs, wcs2->czphs) ||
        !wcsutil_dblEq(naxis, tol, wcs1->cperi, wcs2->cperi) ||
d1532 2
a1533 2
        !wcsutil_dblEq(2, tol,  wcs1->mjdref,    wcs2->mjdref)   ||
        !wcsutil_dblEq(1, tol, &wcs1->timeoffs, &wcs2->timeoffs) ||
d1538 15
a1552 15
        !wcsutil_dblEq(1, tol, &wcs1->mjdobs,   &wcs2->mjdobs)   ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdbeg,   &wcs2->mjdbeg)   ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdavg,   &wcs2->mjdavg)   ||
        !wcsutil_dblEq(1, tol, &wcs1->mjdend,   &wcs2->mjdend)   ||
        !wcsutil_dblEq(1, tol, &wcs1->jepoch,   &wcs2->jepoch)   ||
        !wcsutil_dblEq(1, tol, &wcs1->bepoch,   &wcs2->bepoch)   ||
        !wcsutil_dblEq(1, tol, &wcs1->tstart,   &wcs2->tstart)   ||
        !wcsutil_dblEq(1, tol, &wcs1->tstop,    &wcs2->tstop)    ||
        !wcsutil_dblEq(1, tol, &wcs1->xposure,  &wcs2->xposure)  ||
        !wcsutil_dblEq(1, tol, &wcs1->telapse,  &wcs2->telapse)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timsyer,  &wcs2->timsyer)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timrder,  &wcs2->timrder)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timedel,  &wcs2->timedel)  ||
        !wcsutil_dblEq(1, tol, &wcs1->timepixr, &wcs2->timepixr) ||
        !wcsutil_dblEq(6, tol,  wcs1->obsgeo,    wcs2->obsgeo)   ||
d1555 1
a1555 1
        !wcsutil_dblEq(1, tol, &wcs1->equinox,  &wcs2->equinox)  ||
d1558 2
a1559 2
        !wcsutil_dblEq(1, tol, &wcs1->velosys,  &wcs2->velosys)  ||
        !wcsutil_dblEq(1, tol, &wcs1->zsource,  &wcs2->zsource)  ||
d1561 1
a1561 1
        !wcsutil_dblEq(1, tol, &wcs1->velangl,  &wcs2->velangl)) {
d1567 5
a1571 5
      if (!wcsutil_dblEq(1, tol, &wcs1->aux->rsun_ref, &wcs2->aux->rsun_ref) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->dsun_obs, &wcs2->aux->dsun_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->crln_obs, &wcs2->aux->crln_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->hgln_obs, &wcs2->aux->hgln_obs) ||
          !wcsutil_dblEq(1, tol, &wcs1->aux->hglt_obs, &wcs2->aux->hglt_obs)) {
d1708 1
a1708 222
  return WCSERR_SUCCESS;
}

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

int wcstrim(struct wcsprm *wcs)

{
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (wcs->m_flag != WCSSET) {
    // Nothing to do.
    return WCSERR_SUCCESS;
  }

  if (wcs->flag != WCSSET) {
    return WCSERR_UNSET;
  }

  if (wcs->npv < wcs->npvmax) {
    if (wcs->m_pv) {
      if (wcs->npv == 0) {
        free(wcs->m_pv);
        wcs->pv = wcs->m_pv = 0x0;
      } else {
        size_t size = wcs->npv * sizeof(struct pvcard);
        // No error if realloc() fails, it will leave the array untouched.
        if ((wcs->pv = wcs->m_pv = realloc(wcs->m_pv, size))) {
          wcs->npvmax = wcs->npv;
        }
      }
    }
  }

  if (wcs->nps < wcs->npsmax) {
    if (wcs->m_ps) {
      if (wcs->nps == 0) {
        free(wcs->m_ps);
        wcs->ps = wcs->m_ps = 0x0;
      } else {
        size_t size = wcs->nps * sizeof(struct pscard);
        // No error if realloc() fails, it will leave the array untouched.
        if ((wcs->ps = wcs->m_ps = realloc(wcs->m_ps, size))) {
          wcs->npsmax = wcs->nps;
        }
      }
    }
  }

  if (!(wcs->altlin & 2)) {
    if (wcs->m_cd) {
      free(wcs->m_cd);
      wcs->cd = wcs->m_cd = 0x0;
    }
  }

  if (!(wcs->altlin & 4)) {
    if (wcs->m_crota) {
      free(wcs->m_crota);
      wcs->crota = wcs->m_crota = 0x0;
    }
  }

  if (wcs->colax) {
    if (wcsutil_all_ival(wcs->naxis, 0, wcs->colax)) {
      free(wcs->m_colax);
      wcs->colax = wcs->m_colax = 0x0;
    }
  }

  if (wcs->cname) {
    if (wcsutil_all_sval(wcs->naxis, "", wcs->cname)) {
      free(wcs->m_cname);
      wcs->cname = wcs->m_cname = 0x0;
    }
  }

  if (wcs->crder) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->crder)) {
      free(wcs->m_crder);
      wcs->crder = wcs->m_crder = 0x0;
    }
  }

  if (wcs->csyer) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->csyer)) {
      free(wcs->m_csyer);
      wcs->csyer = wcs->m_csyer = 0x0;
    }
  }

  if (wcs->czphs) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->czphs)) {
      free(wcs->m_czphs);
      wcs->czphs = wcs->m_czphs = 0x0;
    }
  }

  if (wcs->cperi) {
    if (wcsutil_all_dval(wcs->naxis, UNDEFINED, wcs->cperi)) {
      free(wcs->m_cperi);
      wcs->cperi = wcs->m_cperi = 0x0;
    }
  }

  return WCSERR_SUCCESS;
}

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

int wcssize(const struct wcsprm *wcs, int sizes[2])

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

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

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

  int exsizes[2];
  int naxis = wcs->naxis;

  // wcsprm::crpix[].
  sizes[1] += naxis * sizeof(double);

  // wcsprm::pc[].
  sizes[1] += naxis*naxis * sizeof(double);

  // wcsprm::cdelt[].
  sizes[1] += naxis * sizeof(double);

  // wcsprm::crval[].
  sizes[1] += naxis * sizeof(double);

  // wcsprm::cunit[].
  if (wcs->cunit) {
    sizes[1] += naxis * sizeof(char [72]);
  }

  // wcsprm::ctype[].
  sizes[1] += naxis * sizeof(char [72]);

  // wcsprm::pv[].
  if (wcs->pv) {
    sizes[1] += wcs->npvmax * sizeof(struct pvcard);
  }

  // wcsprm::ps[].
  if (wcs->ps) {
    sizes[1] += wcs->npsmax * sizeof(struct pscard);
  }

  // wcsprm::cd[].
  if (wcs->cd) {
    sizes[1] += naxis*naxis * sizeof(double);
  }

  // wcsprm::crota[].
  if (wcs->crota) {
    sizes[1] += naxis * sizeof(double);
  }

  // wcsprm::colax[].
  if (wcs->colax) {
    sizes[1] += naxis * sizeof(int);
  }

  // wcsprm::cname[].
  if (wcs->cname) {
    sizes[1] += naxis * sizeof(char [72]);
  }

  // wcsprm::crder[].
  if (wcs->crder) {
    sizes[1] += naxis * sizeof(double);
  }

  // wcsprm::csyer[].
  if (wcs->csyer) {
    sizes[1] += naxis * sizeof(double);
  }

  // wcsprm::czphs[].
  if (wcs->czphs) {
    sizes[1] += naxis * sizeof(double);
  }

  // wcsprm::cperi[].
  if (wcs->cperi) {
    sizes[1] += naxis * sizeof(double);
  }

  // wcsprm::aux.
  if (wcs->aux) {
    sizes[1] += sizeof(struct auxprm);
  }

  // wcsprm::tab.
  for (int itab = 0; itab < wcs->ntab; itab++) {
    tabsize(wcs->tab + itab, exsizes);
    sizes[1] += exsizes[0] + exsizes[1];
  }

  // wcsprm::wtb.
  if (wcs->wtb) {
    sizes[1] += wcs->nwtb * sizeof(struct wtbarr);
  }

  // wcsprm::lin.
  linsize(&(wcs->lin), exsizes);
  sizes[1] += exsizes[1];

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

  return WCSERR_SUCCESS;
a1712 20
int auxsize(const struct auxprm *aux, int sizes[2])

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

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

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

  return WCSERR_SUCCESS;
}


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

d1738 1
a1738 1
    return WCSERR_SUCCESS;
d2133 1
a2133 1
  return WCSERR_SUCCESS;
d2154 1
a2154 1
  return WCSERR_SUCCESS;
d2171 1
a2171 1
  return WCSERR_SUCCESS;
d2567 1
a2567 1
  return WCSERR_SUCCESS;
d2835 1
a2835 1
  return WCSERR_SUCCESS;
d2909 1
a2909 1
  return WCSERR_SUCCESS;
d3467 1
a3467 1
      if (dabs < tol) return WCSERR_SUCCESS;
d3481 1
a3481 1
      if (dabs < tol) return WCSERR_SUCCESS;
d3512 1
a3512 1
          if (dabs < tol) return WCSERR_SUCCESS;
d3557 1
a3557 1
            if (dabs < tol) return WCSERR_SUCCESS;
d3561 1
a3561 1
              if (dabs < tol2) return WCSERR_SUCCESS;
d3633 1
a3633 1
            if (d0m < tol) return WCSERR_SUCCESS;
d3646 1
a3646 1
            if (d1m < tol) return WCSERR_SUCCESS;
d3684 1
a3684 1
      if (dabs < tol) return WCSERR_SUCCESS;
d3698 1
a3698 1
      if (dabs < tol) return WCSERR_SUCCESS;
d3728 1
a3728 1
          if (dabs < tol) return WCSERR_SUCCESS;
d3773 1
a3773 1
            if (dabs < tol) return WCSERR_SUCCESS;
d3777 1
a3777 1
              if (dabs < tol2) return WCSERR_SUCCESS;
d3849 1
a3849 1
            if (d0m < tol) return WCSERR_SUCCESS;
d3862 1
a3862 1
            if (d1m < tol) return WCSERR_SUCCESS;
d3940 1
a3940 1
      return WCSERR_SUCCESS;
d3965 1
a3965 1
        return WCSERR_SUCCESS;
d4003 1
a4003 1
        return WCSERR_SUCCESS;
d4206 1
a4206 1
  return WCSERR_SUCCESS;
d4272 1
a4272 1
  return WCSERR_SUCCESS;
@


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: wcs.c,v 7.3.1.5 2021/01/28 12:29:30 mcalabre Exp mcalabre $
d4024 184
@


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


7.4.1.2
log
@Added new function wcsccs().
@
text
@d22 1
a22 1
  $Id: wcs.c,v 7.4.1.1 2021/01/31 02:26:24 mcalabre Exp mcalabre $
a4023 184
}

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

int wcsccs(
  struct wcsprm *wcs,
  double lng2P1,
  double lat2P1,
  double lng1P2,
  const char *clng,
  const char *clat,
  const char *radesys,
  double equinox,
  const char *alt)

{
  static const char *function = "wcsccs";

  // Initialize if required.
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  struct wcserr **err = &(wcs->err);

  if (wcs->flag != WCSSET) {
    int status;
    if ((status = wcsset(wcs))) return status;
  }

  if (wcs->lng < 0 || wcs->lat < 0) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_SUBIMAGE),
      "Image does not have celestial axes.");
  }

  // (lng1XX,lat1XX)  ...longitude and latitude of XX in the old system.
  // (lng2XX,lat2XX)  ...longitude and latitude of XX in the new system.
  // XX = NP          ...natuve pole,
  //      P1          ...pole of the old system,
  //      P2          ...pole of the new system,
  //      FP          ...fiducial point.

  // Set up the transformation from the old to the new system.
  double euler12[5];
  euler12[0] = lng2P1;
  euler12[1] = 90.0 - lat2P1;
  euler12[2] = lng1P2;
  euler12[3] = cosd(euler12[1]);
  euler12[4] = sind(euler12[1]);

  // Transform coordinates of the fiducial point (FP) to the new system.
  double lng1FP = wcs->crval[wcs->lng];
  double lat1FP = wcs->crval[wcs->lat];
  double lng2FP, lat2FP;
  (void)sphx2s(euler12, 1, 1, 1, 1, &lng1FP, &lat1FP, &lng2FP, &lat2FP);

  // Compute native coordinates of the new pole (noting lat1P2 == lat2P1).
  double phiP2, thetaP2;
  (void)sphs2x(wcs->cel.euler, 1, 1, 1, 1, &lng1P2, &lat2P1,
               &phiP2, &thetaP2);

  if (fabs(lat2FP) == 90.0 || fabs(thetaP2) == 90.0) {
    // If one of the poles of the new system is at the fiducial point, then
    // lng2FP is indeterminate, and if one of them is at the native pole, then
    // phiP2 is indeterminate.  We have to work harder to obtain these values.

    // Compute coordinates of the native pole (NP) in the old and new systems.
    double phiNP = 0.0, thetaNP = 90.0;
    double lng1NP, lat1NP;
    (void)sphx2s(wcs->cel.euler, 1, 1, 1, 1, &phiNP, &thetaNP,
                 &lng1NP, &lat1NP);

    double lng2NP, lat2NP;
    (void)sphx2s(euler12, 1, 1, 1, 1, &lng1NP, &lat1NP, &lng2NP, &lat2NP);

    // Native latitude and longitude of the fiducial point, (phi0,theta0).
    double phiFP   = wcs->cel.prj.phi0;
    double thetaFP = wcs->cel.prj.theta0;

    if (fabs(lat2NP) == 90.0) {
      // Following WCS Paper II equations (3) and (4), we are free to choose
      // phiP2 and set lng2NP accordingly.  So set phiP2 to its default value
      // for the projection.
      if (thetaFP < lat2FP) {
        phiP2 = 0.0;
      } else {
        phiP2 = 180.0;
      }

      // Compute coordinates in the old system of test point X.
      double phiX = 0.0, thetaX = 0.0;
      double lng1X, lat1X;
      (void)sphx2s(wcs->cel.euler, 1, 1, 1, 1, &phiX, &thetaX,
                   &lng1X, &lat1X);

      // Ensure that lng1X is not indeterminate.
      if (fabs(lat1X) == 90.0) {
        phiX = 90.0;
        (void)sphx2s(wcs->cel.euler, 1, 1, 1, 1, &phiX, &thetaX,
                     &lng1X, &lat1X);
      }

      // Compute coordinates in the new system of test point X.
      double lng2X, lat2X;
      (void)sphx2s(euler12, 1, 1, 1, 1, &lng1X, &lat1X, &lng2X, &lat2X);

      // Apply WCS Paper II equations (3) and (4).
      if (lat2NP == +90.0) {
        lng2NP = lng2X + (phiP2 - phiX) + 180.0;
      } else {
        lng2NP = lng2X - (phiP2 - phiX);
      }

    } else {
      // For (lng2NP + 90, 0), WCS Paper II equation (5) reduces to
      // phi = phiP2 - 90.
      double lng2X = lng2NP + 90.0;
      double lat2X = 0.0;
      double lng1X, lat1X;
      (void)sphs2x(euler12, 1, 1, 1, 1, &lng2X, &lat2X, &lng1X, &lat1X);

      double phiX, thetaX;
      (void)sphs2x(wcs->cel.euler, 1, 1, 1, 1, &lng1X, &lat1X,
                   &phiX, &thetaX);

      phiP2 = phiX + 90.0;
    }

    // Compute the longitude of the fiducial point in the new system.
    double eulerN2[5];
    eulerN2[0] = lng2NP;
    eulerN2[1] = 90.0 - lat2NP;
    eulerN2[2] = phiP2;
    eulerN2[3] = cosd(eulerN2[1]);
    eulerN2[4] = sind(eulerN2[1]);

    (void)sphx2s(eulerN2, 1, 1, 1, 1, &phiFP, &thetaFP, &lng2FP, &lat2FP);
  }

  // Update reference values in wcsprm.
  wcs->flag = 0;
  wcs->crval[wcs->lng] = lng2FP;
  wcs->crval[wcs->lat] = lat2FP;
  wcs->lonpole = phiP2;
  wcs->latpole = thetaP2;

  // Update wcsprm::ctype.
  if (clng) {
    strncpy(wcs->ctype[wcs->lng], clng, 4);
    for (int i = 0; i < 4; i++) {
      if (wcs->ctype[wcs->lng][i] == '\0') {
        wcs->ctype[wcs->lng][i] = '-';
      }
    }
  }

  if (clat) {
    strncpy(wcs->ctype[wcs->lat], clat, 4);
    for (int i = 0; i < 4; i++) {
      if (wcs->ctype[wcs->lat][i] == '\0') {
        wcs->ctype[wcs->lat][i] = '-';
      }
    }
  }

  // Update auxiliary values.
  if (strncmp(wcs->ctype[wcs->lng], "RA--", 4) == 0 &&
      strncmp(wcs->ctype[wcs->lat], "DEC-", 4) == 0) {
    // Transforming to equatorial coordinates.
    if (radesys) {
      strncpy(wcs->radesys, radesys, 71);
    }

    if (equinox != 0.0) {
      wcs->equinox = equinox;
    }
  } else {
    // Meaningless for other than equatorial coordinates.
    memset(wcs->radesys, 0, 72);
    wcs->equinox = UNDEFINED;
  }

  if (alt && *alt) {
    wcs->alt[0] = *alt;
  }

  return 0;
@


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: wcs.c,v 7.2.1.1 2020/03/09 07:34:50 mcalabre Exp mcalabre $
d49 1
a49 1
/* Maximum number of PVi_ma and PSi_ma keywords. */
d53 1
a53 1
/* Map status return value to message. */
d70 1
a70 1
/* Map error returns for lower-level routines. */
d72 7
a78 7
  WCSERR_SUCCESS,		/*  0: LINERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: LINERR_NULL_POINTER    */
  WCSERR_MEMORY,		/*  2: LINERR_MEMORY          */
  WCSERR_SINGULAR_MTX,		/*  3: LINERR_SINGULAR_MTX    */
  WCSERR_BAD_PARAM,		/*  4: LINERR_DISTORT_INIT    */
  WCSERR_BAD_PIX,		/*  5: LINERR_DISTORT         */
  WCSERR_BAD_WORLD		/*  6: LINERR_DEDISTORT       */
d82 5
a86 5
  WCSERR_SUCCESS,		/*  0: LOGERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: LOGERR_NULL_POINTER    */
  WCSERR_BAD_PARAM,		/*  2: LOGERR_BAD_LOG_REF_VAL */
  WCSERR_BAD_PIX,		/*  3: LOGERR_BAD_X           */
  WCSERR_BAD_WORLD		/*  4: LOGERR_BAD_WORLD       */
d90 6
a95 6
				/* -1: SPCERR_NO_CHANGE       */
  WCSERR_SUCCESS,		/*  0: SPCERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: SPCERR_NULL_POINTER    */
  WCSERR_BAD_PARAM,		/*  2: SPCERR_BAD_SPEC_PARAMS */
  WCSERR_BAD_PIX,		/*  3: SPCERR_BAD_X           */
  WCSERR_BAD_WORLD		/*  4: SPCERR_BAD_SPEC        */
d99 7
a105 7
  WCSERR_SUCCESS,		/*  0: CELERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: CELERR_NULL_POINTER    */
  WCSERR_BAD_PARAM,		/*  2: CELERR_BAD_PARAM       */
  WCSERR_BAD_COORD_TRANS,	/*  3: CELERR_BAD_COORD_TRANS */
  WCSERR_ILL_COORD_TRANS,	/*  4: CELERR_ILL_COORD_TRANS */
  WCSERR_BAD_PIX,		/*  5: CELERR_BAD_PIX         */
  WCSERR_BAD_WORLD		/*  6: CELERR_BAD_WORLD       */
d109 6
a114 6
  WCSERR_SUCCESS,		/*  0: TABERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: TABERR_NULL_POINTER    */
  WCSERR_MEMORY,		/*  2: TABERR_MEMORY          */
  WCSERR_BAD_PARAM,		/*  3: TABERR_BAD_PARAMS      */
  WCSERR_BAD_PIX,		/*  4: TABERR_BAD_X           */
  WCSERR_BAD_WORLD		/*  5: TABERR_BAD_WORLD       */
d117 1
a117 1
/* Convenience macro for invoking wcserr_set(). */
d124 1
a124 1
/* Internal helper functions, not for general use. */
d128 1
a128 1
/*--------------------------------------------------------------------------*/
d133 1
a133 1
/*--------------------------------------------------------------------------*/
d141 1
a141 1
/*--------------------------------------------------------------------------*/
d158 1
a158 1
  /* Check inputs. */
d165 1
a165 1
  /* Initialize error message handling... */
d172 3
a174 3
  /* ...and also in the contained structs in case we have to return due to
     an error before they can be initialized by their specialized routines,
     since wcsperr() assumes their wcserr pointers are valid. */
d185 1
a185 1
  /* Initialize pointers. */
d193 1
a193 1
    /* Initialize memory management. */
d223 1
a223 1
  /* Allocate memory for arrays if required. */
d242 1
a242 1
    /* Was sufficient allocated previously? */
d247 1
a247 1
      /* No, free it. */
d253 1
a253 1
        /* In case the caller fiddled with it. */
d269 1
a269 1
        /* In case the caller fiddled with it. */
d286 1
a286 1
        /* In case the caller fiddled with it. */
d303 1
a303 1
        /* In case the caller fiddled with it. */
d320 1
a320 1
        /* In case the caller fiddled with it. */
d337 1
a337 1
        /* In case the caller fiddled with it. */
d354 1
a354 1
        /* In case the caller fiddled with it. */
d377 1
a377 1
        /* In case the caller fiddled with it. */
d400 1
a400 1
        /* In case the caller fiddled with it. */
d417 1
a417 1
        /* In case the caller fiddled with it. */
d434 1
a434 1
        /* In case the caller fiddled with it. */
d451 1
a451 1
        /* In case the caller fiddled with it. */
d468 1
a468 1
        /* In case the caller fiddled with it. */
d485 1
a485 1
        /* In case the caller fiddled with it. */
d502 1
a502 1
        /* In case the caller fiddled with it. */
d519 1
a519 1
        /* In case the caller fiddled with it. */
d540 1
a540 1
  /* Set defaults for the linear transformation. */
d549 1
a549 1
  /* CRVALia defaults to 0.0. */
d555 1
a555 1
  /* CUNITia and CTYPEia are blank by default. */
d562 1
a562 1
  /* Set defaults for the celestial transformation parameters. */
d566 1
a566 1
  /* Set defaults for the spectral transformation parameters. */
d570 1
a570 1
  /* Default parameter values. */
d585 1
a585 1
  /* Defaults for alternate linear transformations. */
d598 1
a598 1
  /* Defaults for auxiliary coordinate system information. */
d661 1
a661 1
  /* No additional auxiliary coordinate system information. */
d664 1
a664 1
  /* Tabular parameters. */
d670 1
a670 1
  /* Reset derived values. */
d684 1
a684 1
/*--------------------------------------------------------------------------*/
d696 1
a696 1
  /* Check inputs. */
d700 1
a700 1
  /* Allocate memory if required. */
d703 1
a703 1
      /* In case the caller fiddled with it. */
d725 1
a725 1
/*--------------------------------------------------------------------------*/
d753 1
a753 1
  /* N.B. we do not rely on the wcsprm struct having been set up. */
d766 1
a766 1
  /* Allocate enough temporary storage to hold either axes[] xor map[].*/
d773 1
a773 1
    /* Construct an index array. */
d784 1
a784 1
  /* So that we don't try to free uninitialized pointers on cleanup. */
d794 1
a794 1
      /* Subimage extraction by type. */
d815 1
a815 1
        /* Find the last non-blank character. */
d874 1
a874 1
        /* This axis is wanted, but has it already been added? */
d884 1
a884 1
      /* Check that the requested axis has not already been added. */
d893 1
a893 1
      /* Graft on a new axis. */
d903 1
a903 1
    /* Zero out this struct. */
d913 5
a917 5
  /* Construct the inverse axis map (i is 0-relative, j is 1-relative):
     axes[i] == j means that output axis i+1 comes from input axis j,
     axes[i] == 0 means to create a new axis,
      map[i] == j means that input axis i+1 goes to output axis j,
      map[i] == 0 means that input axis i+1 is not used. */
d930 2
a931 2
  /* Check that the subimage coordinate system is separable.  First check */
  /* non-zero, off-diagonal elements of the linear transformation matrix. */
d944 2
a945 2
  /* Now check for distortions that depend on other axes.  As the disprm    */
  /* struct may not have been initialized, we must parse the dpkey entries. */
d959 1
a959 1
        /* Axis numbers in axmap[] are 0-relative. */
d967 1
a967 1
          /* Thorough error checking will be done later by disset(). */
d994 1
a994 1
            /* Make room for an additional DPja.AXIS.j record. */
d999 1
a999 1
            /* Distortion depends on an axis excluded from the subimage. */
d1011 1
a1011 1
  /* Number of PVi_ma records in the subimage. */
d1020 1
a1020 1
  /* Number of PSi_ma records in the subimage. */
d1029 1
a1029 1
  /* Initialize the destination. */
d1046 1
a1046 1
      /* Also inits disdst. */
d1057 1
a1057 1
  /* Linear transformation. */
d1087 1
a1087 1
  /* Coordinate reference value. */
d1097 1
a1097 1
  /* Coordinate units and type. */
d1106 1
a1106 1
  /* Celestial and spectral transformation parameters. */
d1112 1
a1112 1
  /* Parameter values. */
d1117 1
a1117 1
      /* i == 0 is a special code that means "the latitude axis". */
d1140 1
a1140 1
  /* Alternate linear transformations. */
d1149 2
a1150 2
        /* A new axis is being created where CDi_ja was present in the input
           header, so override the default value of 0 set by wcsinit(). */
d1168 1
a1168 1
  /* Auxiliary coordinate system information. */
d1236 1
a1236 1
  /* Additional auxiliary coordinate system information. */
d1253 1
a1253 1
  /* Coordinate lookup tables; only copy what's needed. */
d1256 1
a1256 1
    /* Is this table wanted? */
d1268 1
a1268 1
    /* Allocate memory for tabprm structs. */
d1297 1
a1297 1
  /* Distortion parameters (in linprm). */
d1310 1
a1310 1
      /* Distortion type and maximum distortion (but not total distortion). */
d1319 1
a1319 1
      /* DPja or DQia keyvalues. */
d1325 1
a1325 1
        /* Determine the axis mapping. */
d1352 1
a1352 1
        /* Copy the DPja or DQia keyvalues. */
d1361 1
a1361 1
            /* Skip it, we will create our own later. */
d1416 1
a1416 1
/*--------------------------------------------------------------------------*/
d1445 1
a1445 1
    /* Don't compare crpix. */
d1473 1
a1473 1
  /* Compare pv cards, which may not be in the same order */
d1484 1
a1484 1
    /* We didn't find a match, so they are not equal */
d1490 1
a1490 1
  /* Compare ps cards, which may not be in the same order */
d1501 1
a1501 1
    /* We didn't find a match, so they are not equal */
d1565 1
a1565 1
    /* Compare additional auxiliary parameters. */
d1579 1
a1579 1
  /* Compare tabular parameters */
d1597 1
a1597 1
/*--------------------------------------------------------------------------*/
d1610 1
a1610 1
    /* Optionally allocated by wcsinit() for given parameters. */
d1612 1
a1612 1
      /* Start by cleaning the slate. */
d1634 1
a1634 1
      /* Now release the memory. */
d1652 1
a1652 1
      /* May have been allocated by wcspih() or wcssub(). */
d1655 1
a1655 1
      /* Allocated unconditionally by wcstab(). */
d1666 1
a1666 1
    /* Allocated unconditionally by wcsset(). */
d1713 1
a1713 1
/*--------------------------------------------------------------------------*/
d1755 1
a1755 1
  /* Linear transformation. */
d1766 1
a1766 1
  /* Coordinate increment at reference point. */
d1774 1
a1774 1
  /* Coordinate value at reference point. */
d1782 1
a1782 1
  /* Coordinate units and type. */
d1793 1
a1793 1
  /* Celestial and spectral transformation parameters. */
d1803 1
a1803 1
  /* Parameter values. */
d1819 1
a1819 1
  /* Alternate linear transformations. */
d1846 1
a1846 1
  /* Auxiliary coordinate system information. */
d1990 1
a1990 1
  /* Additional auxiliary coordinate system information. */
d2009 1
a2009 1
  /* Derived values. */
d2032 1
a2032 1
  /* Memory management. */
d2094 1
a2094 1
  /* Tabular transformation parameters. */
d2122 1
a2122 1
  /* Linear transformation parameters. */
d2127 1
a2127 1
  /* Celestial transformation parameters. */
d2132 1
a2132 1
  /* Spectral transformation parameters. */
d2140 1
a2140 1
/*--------------------------------------------------------------------------*/
d2163 1
a2163 1
/*--------------------------------------------------------------------------*/
d2181 1
a2181 1
/*--------------------------------------------------------------------------*/
d2204 1
a2204 1
  /* Determine axis types from CTYPEia. */
d2209 1
a2209 1
  /* Convert to canonical units. */
d2221 1
a2221 1
  /* Non-linear celestial axes present? */
d2225 1
a2225 1
    /* CRVALia, LONPOLEa, and LATPOLEa keyvalues. */
d2231 1
a2231 1
    /* Do alias translation for TPU/TPV before dealing with PVi_ma. */
d2236 1
a2236 1
      /* Translate the PV parameters. */
d2243 1
a2243 1
      /* Attach it to linprm.  Also inits it. */
d2246 1
a2246 1
        /* Prior distortion. */
d2250 1
a2250 1
        /* Sequent distortion. */
d2255 1
a2255 1
      /* Yes, the distortion type is "TPV" even for TPU. */
d2259 1
a2259 1
      /* Keep the keywords in axis-order to aid debugging. */
d2269 1
a2269 1
      /* Copy distortion parameters for the longitude axis. */
d2277 1
a2277 1
      /* Now the latitude axis. */
d2291 1
a2291 1
      /* Erase PVi_ma associated with the celestial axes. */
d2307 2
a2308 2
      /* As the PVi_ma have now been erased, ctype must be reset to prevent
         this translation from re-occurring if wcsset() is called again. */
d2313 1
a2313 1
      /* The WAT distortion should already have been encoded in disseq. */
d2319 1
a2319 1
      /* The WAT distortion should already have been encoded in disseq. */
d2325 1
a2325 1
    /* PVi_ma keyvalues. */
d2328 1
a2328 1
        /* From a PROJPn keyword. */
d2336 1
a2336 1
        /* PVi_ma associated with latitude axis. */
d2342 1
a2342 1
        /* PVi_ma associated with longitude axis. */
d2354 1
a2354 1
          /* If present, overrides LONPOLEa. */
d2358 1
a2358 1
          /* If present, overrides LATPOLEa. */
d2370 1
a2370 1
    /* Do simple alias translations. */
d2378 1
a2378 1
      /* Convert NCP to SIN. */
d2389 1
a2389 1
    /* Initialize the celestial transformation routines. */
d2395 1
a2395 1
    /* Update LONPOLE, LATPOLE, and PVi_ma keyvalues. */
d2423 1
a2423 1
  /* Non-linear spectral axis present? */
d2433 1
a2433 1
    /* CRVALia, RESTFRQa, and RESTWAVa keyvalues. */
d2438 1
a2438 1
    /* PVi_ma keyvalues. */
d2444 1
a2444 1
        /* PVi_ma associated with grism axis. */
d2451 1
a2451 1
    /* Initialize the spectral transformation routines. */
d2458 1
a2458 1
  /* Tabular axes present? */
d2466 1
a2466 1
  /* Initialize the linear transformation. */
d2472 1
a2472 1
      /* Copy CDi_ja to PCi_ja and reset CDELTia. */
d2482 1
a2482 1
      /* Construct PCi_ja from CROTAia. */
d2508 1
a2508 1
  /* Set defaults for radesys and equinox for equatorial or ecliptic. */
d2523 1
a2523 1
      /* Equinox is not applicable for these coordinate systems. */
d2536 1
a2536 1
    /* No celestial axes, ensure that radesys and equinox are unset. */
d2542 1
a2542 1
  /* Strip off trailing blanks and null-fill auxiliary string members. */
d2566 1
a2566 1
  /* MJDREF defaults to zero if no reference date keywords were defined. */
d2581 1
a2581 1
/* : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :  */
d2599 1
a2599 1
  /* Parse the CTYPEia keyvalues. */
d2617 1
a2617 1
    /* Null fill. */
d2623 1
a2623 1
    /* Check for early Paper IV syntax (e.g. '-SIP' used by Spitzer). */
d2625 1
a2625 1
      /* Excise the "4-3-3" or "8-3"-form distortion code. */
d2628 1
a2628 1
      /* Remove trailing dashes from "8-3"-form codes. */
d2635 1
a2635 1
    /* Logarithmic or tabular axis? */
d2638 1
a2638 1
      /* Logarithmic axis. */
d2642 1
a2642 1
      /* Tabular axis. */
d2647 1
a2647 1
      /* Could have -LOG or -TAB with celestial or spectral types. */
d2650 1
a2650 1
      /* Take care of things like 'FREQ-LOG' or 'RA---TAB'. */
d2657 1
a2657 1
    /* Translate AIPS spectral types for spctyp(). */
d2663 1
a2663 1
    /* Process linear axes. */
d2665 1
a2665 1
      /* Identify Stokes, celestial and spectral types. */
d2667 1
a2667 1
        /* STOKES axis. */
d2673 1
a2673 1
        /* Longitude axis. */
d2683 1
a2683 1
        /* Latitude axis. */
d2691 1
a2691 1
        /* CUBEFACE axis. */
d2696 1
a2696 1
          /* Multiple CUBEFACE axes! */
d2703 1
a2703 1
        /* Spectral axis. */
d2712 1
a2712 1
    /* CTYPEia is in "4-3" form; is it a recognized spectral type? */
d2714 1
a2714 1
      /* Non-linear spectral axis found. */
d2717 1
a2717 1
      /* Check uniqueness. */
d2730 1
a2730 1
    /* Is it a recognized celestial projection? */
d2736 1
a2736 1
      /* Not a standard projection code, maybe it's an alias. */
d2742 1
a2742 1
        /* Not a recognized algorithm code of any type. */
d2750 1
a2750 1
    /* Parse the celestial axis type. */
d2753 1
a2753 1
      /* The first of the two celestial axes. */
d2793 1
a2793 1
        /* Unrecognized celestial type. */
d2806 1
a2806 1
      /* Looking for the complementary celestial axis. */
d2810 1
a2810 1
        /* Inconsistent projection types. */
d2823 1
a2823 1
  /* Do we have a complementary pair of celestial axes? */
d2825 1
a2825 1
    /* Unmatched celestial axis. */
d2832 1
a2832 1
  /* Table group numbers. */
d2835 1
a2835 1
      /* Get image axis number. */
d2850 1
a2850 1
/* : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :  */
d2867 1
a2867 1
    /* Use types set by wcs_types(). */
d2870 1
a2870 1
      /* Celestial axis. */
d2875 1
a2875 1
      /* Spectral axis. */
d2885 1
a2885 1
    /* Tabular axis, CDELTia and CRVALia relate to indices. */
d2894 6
a2899 3
        wcserr_set(WCSERR_SET(WCSERR_BAD_COORD_TRANS),
          "In CUNIT%d%.1s: %s", i+1, (*wcs->alt)?wcs->alt:"", uniterr->msg);
        free(uniterr);
d2922 1
a2922 1
/*--------------------------------------------------------------------------*/
d2946 1
a2946 1
  /* Initialize if required. */
d2954 1
a2954 1
  /* Sanity check. */
d2961 1
a2961 1
  /* Apply pixel-to-world linear transformation. */
d2966 1
a2966 1
  /* Initialize status vectors. */
d2975 1
a2975 1
  /* Convert intermediate world coordinates to world coordinates. */
d2977 1
a2977 1
    /* Extract the second digit of the axis type code. */
d2981 1
a2981 1
      /* Linear or quantized coordinate axis. */
d2992 1
a2992 1
      /* Convert celestial coordinates; do we have a CUBEFACE axis? */
d2994 1
a2994 1
        /* Separation between faces. */
d3001 1
a3001 1
        /* Lay out faces in a plane. */
d3042 1
a3042 1
      /* Check for constant x and/or y. */
d3054 1
a3054 1
      /* Transform projection plane coordinates to celestial coordinates. */
d3066 1
a3066 1
      /* If x and y were both constant, replicate values. */
d3081 1
a3081 1
      /* Check for constant x. */
d3089 1
a3089 1
        /* Spectral coordinates. */
d3099 1
a3099 1
        /* Logarithmic coordinates. */
d3110 1
a3110 1
      /* If x was constant, replicate values. */
d3123 1
a3123 1
  /* Do tabular coordinates. */
d3144 1
a3144 1
  /* Zero the unused world coordinate elements. */
d3155 1
a3155 1
/*--------------------------------------------------------------------------*/
d3181 1
a3181 1
  /* Initialize if required. */
d3189 1
a3189 1
  /* Sanity check. */
d3195 1
a3195 1
  /* Initialize status vectors. */
d3205 1
a3205 1
  /* Convert world coordinates to intermediate world coordinates. */
d3207 1
a3207 1
    /* Extract the second digit of the axis type code. */
d3211 1
a3211 1
      /* Linear or quantized coordinate axis. */
d3222 1
a3222 1
      /* Celestial coordinates; check for constant lng and/or lat. */
d3234 1
a3234 1
      /* Transform celestial coordinates to projection plane coordinates. */
d3246 1
a3246 1
      /* If lng and lat were both constant, replicate values. */
d3260 1
a3260 1
      /* Do we have a CUBEFACE axis? */
d3262 1
a3262 1
        /* Separation between faces. */
d3269 1
a3269 1
        /* Stack faces in a cube. */
d3296 1
a3296 1
      /* Check for constancy. */
d3304 1
a3304 1
        /* Spectral coordinates. */
d3314 1
a3314 1
        /* Logarithmic coordinates. */
d3325 1
a3325 1
      /* If constant, replicate values. */
d3338 1
a3338 1
  /* Do tabular coordinates. */
d3359 1
a3359 1
  /* Zero the unused intermediate world coordinate elements. */
d3366 1
a3366 1
  /* Apply world-to-pixel linear transformation. */
d3377 1
a3377 1
/*--------------------------------------------------------------------------*/
d3411 1
a3411 1
  /* Initialize if required. */
d3423 1
a3423 1
  /* Check vspan. */
d3428 1
a3428 1
    /* Swap them. */
d3433 1
a3433 1
  /* Check vstep. */
d3440 1
a3440 1
  /* Check viter. */
d3448 1
a3448 1
  /* Given pixel element. */
d3451 1
a3451 1
  /* Iterate on the step size. */
d3455 1
a3455 1
    /* Iterate on the sky coordinate between the specified range. */
d3457 1
a3457 1
      /* Celestial longitude is given. */
d3459 1
a3459 1
      /* Check whether the solution interval is a crossing interval. */
d3491 1
a3491 1
      /* Check for a crossing point. */
d3501 1
a3501 1
        /* Refine the solution interval. */
d3515 1
a3515 1
          /* Check for a solution. */
d3519 1
a3519 1
          /* Record the point of closest approach. */
d3525 1
a3525 1
          /* Check for a crossing point. */
d3532 1
a3532 1
          /* Advance to the next subinterval. */
d3538 1
a3538 1
          /* A crossing point was found. */
d3540 1
a3540 1
            /* Use regula falsi division of the interval. */
d3559 1
a3559 1
            /* Check for a solution. */
d3565 1
a3565 1
              /* An artifact of numerical imprecision. */
d3568 1
a3568 1
              /* Must be a discontinuity. */
d3572 1
a3572 1
            /* Record the point of closest approach. */
d3587 1
a3587 1
          /* No convergence, must have been a discontinuity. */
d3594 1
a3594 1
          /* No crossing point; look for a tangent point. */
d3674 1
a3674 1
      /* Celestial latitude is given. */
d3676 1
a3676 1
      /* Check whether the solution interval is a crossing interval. */
d3707 1
a3707 1
      /* Check for a crossing point. */
d3717 1
a3717 1
        /* Refine the solution interval. */
d3731 1
a3731 1
          /* Check for a solution. */
d3735 1
a3735 1
          /* Record the point of closest approach. */
d3741 1
a3741 1
          /* Check for a crossing point. */
d3748 1
a3748 1
          /* Advance to the next subinterval. */
d3754 1
a3754 1
          /* A crossing point was found. */
d3756 1
a3756 1
            /* Use regula falsi division of the interval. */
d3775 1
a3775 1
            /* Check for a solution. */
d3781 1
a3781 1
              /* An artifact of numerical imprecision. */
d3784 1
a3784 1
              /* Must be a discontinuity. */
d3788 1
a3788 1
            /* Record the point of closest approach. */
d3803 1
a3803 1
          /* No convergence, must have been a discontinuity. */
d3810 1
a3810 1
          /* No crossing point; look for a tangent point. */
d3892 1
a3892 1
  /* Set cel0 to the unity transformation. */
d3900 1
a3900 1
  /* No convergence, check for aberrant behaviour at a native pole. */
d3903 1
a3903 1
    /* Could the celestial coordinate element map to a native pole? */
d3922 1
a3922 1
    /* Is there a solution for the given pixel coordinate element? */
d3926 1
a3926 1
    /* Feed native coordinates to wcss2p() with cel0 set to unity. */
d3940 1
a3940 1
    /* Check for a solution. */
d3942 1
a3942 1
      /* Recall saved world coordinates. */
d3948 1
a3948 1
    /* Search for a crossing interval. */
d3964 1
a3964 1
      /* Check for a solution. */
d3967 1
a3967 1
        /* Recall saved world coordinates. */
d3973 1
a3973 1
      /* Is it a crossing interval? */
d3981 1
a3981 1
      /* Use regula falsi division of the interval. */
d4001 1
a4001 1
      /* Check for a solution. */
d4005 1
a4005 1
        /* Recall saved world coordinates. */
d4022 1
a4022 1
  /* No solution. */
d4026 1
a4026 1
/*--------------------------------------------------------------------------*/
d4040 1
a4040 1
  /* Initialize if required. */
d4050 1
a4050 1
      /* Look for a linear spectral axis. */
d4058 1
a4058 1
        /* No spectral axis. */
d4067 1
a4067 1
  /* Translate the spectral axis. */
d4075 1
a4075 1
  /* Translate keyvalues. */
d4082 1
a4082 1
  /* This keeps things tidy if the spectral axis is linear. */
d4089 1
a4089 1
/*--------------------------------------------------------------------------*/
@


7.3.1.1
log
@WCSLIB 7.3 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 7.3.1.1 2020/06/03 03:38:10 mcalabre Exp mcalabre $
d52 1
a52 1
// Maximum number of PVi_ma and PSi_ma keywords.
d56 1
a56 1
// Map status return value to message.
d73 1
a73 1
// Map error returns for lower-level routines.
d75 7
a81 7
  WCSERR_SUCCESS,		//  0: LINERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: LINERR_NULL_POINTER
  WCSERR_MEMORY,		//  2: LINERR_MEMORY
  WCSERR_SINGULAR_MTX,		//  3: LINERR_SINGULAR_MTX
  WCSERR_BAD_PARAM,		//  4: LINERR_DISTORT_INIT
  WCSERR_BAD_PIX,		//  5: LINERR_DISTORT
  WCSERR_BAD_WORLD		//  6: LINERR_DEDISTORT
d85 5
a89 5
  WCSERR_SUCCESS,		//  0: LOGERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: LOGERR_NULL_POINTER
  WCSERR_BAD_PARAM,		//  2: LOGERR_BAD_LOG_REF_VAL
  WCSERR_BAD_PIX,		//  3: LOGERR_BAD_X
  WCSERR_BAD_WORLD		//  4: LOGERR_BAD_WORLD
d93 6
a98 6
				// -1: SPCERR_NO_CHANGE
  WCSERR_SUCCESS,		//  0: SPCERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: SPCERR_NULL_POINTER
  WCSERR_BAD_PARAM,		//  2: SPCERR_BAD_SPEC_PARAMS
  WCSERR_BAD_PIX,		//  3: SPCERR_BAD_X
  WCSERR_BAD_WORLD		//  4: SPCERR_BAD_SPEC
d102 7
a108 7
  WCSERR_SUCCESS,		//  0: CELERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: CELERR_NULL_POINTER
  WCSERR_BAD_PARAM,		//  2: CELERR_BAD_PARAM
  WCSERR_BAD_COORD_TRANS,	//  3: CELERR_BAD_COORD_TRANS
  WCSERR_ILL_COORD_TRANS,	//  4: CELERR_ILL_COORD_TRANS
  WCSERR_BAD_PIX,		//  5: CELERR_BAD_PIX
  WCSERR_BAD_WORLD		//  6: CELERR_BAD_WORLD
d112 6
a117 6
  WCSERR_SUCCESS,		//  0: TABERR_SUCCESS
  WCSERR_NULL_POINTER,		//  1: TABERR_NULL_POINTER
  WCSERR_MEMORY,		//  2: TABERR_MEMORY
  WCSERR_BAD_PARAM,		//  3: TABERR_BAD_PARAMS
  WCSERR_BAD_PIX,		//  4: TABERR_BAD_X
  WCSERR_BAD_WORLD		//  5: TABERR_BAD_WORLD
d120 1
a120 1
// Convenience macro for invoking wcserr_set().
d127 1
a127 1
// Internal helper functions, not for general use.
d131 1
a131 1
//----------------------------------------------------------------------------
d136 1
a136 1
//----------------------------------------------------------------------------
d144 1
a144 1
//----------------------------------------------------------------------------
d161 1
a161 1
  // Check inputs.
d168 1
a168 1
  // Initialize error message handling...
d175 3
a177 3
  // ...and also in the contained structs in case we have to return due to
  // an error before they can be initialized by their specialized routines,
  // since wcsperr() assumes their wcserr pointers are valid.
d188 1
a188 1
  // Initialize pointers.
d196 1
a196 1
    // Initialize memory management.
d226 1
a226 1
  // Allocate memory for arrays if required.
d245 1
a245 1
    // Was sufficient allocated previously?
d250 1
a250 1
      // No, free it.
d256 1
a256 1
        // In case the caller fiddled with it.
d272 1
a272 1
        // In case the caller fiddled with it.
d289 1
a289 1
        // In case the caller fiddled with it.
d306 1
a306 1
        // In case the caller fiddled with it.
d323 1
a323 1
        // In case the caller fiddled with it.
d340 1
a340 1
        // In case the caller fiddled with it.
d357 1
a357 1
        // In case the caller fiddled with it.
d380 1
a380 1
        // In case the caller fiddled with it.
d403 1
a403 1
        // In case the caller fiddled with it.
d420 1
a420 1
        // In case the caller fiddled with it.
d437 1
a437 1
        // In case the caller fiddled with it.
d454 1
a454 1
        // In case the caller fiddled with it.
d471 1
a471 1
        // In case the caller fiddled with it.
d488 1
a488 1
        // In case the caller fiddled with it.
d505 1
a505 1
        // In case the caller fiddled with it.
d522 1
a522 1
        // In case the caller fiddled with it.
d543 1
a543 1
  // Set defaults for the linear transformation.
d552 1
a552 1
  // CRVALia defaults to 0.0.
d558 1
a558 1
  // CUNITia and CTYPEia are blank by default.
d565 1
a565 1
  // Set defaults for the celestial transformation parameters.
d569 1
a569 1
  // Set defaults for the spectral transformation parameters.
d573 1
a573 1
  // Default parameter values.
d588 1
a588 1
  // Defaults for alternate linear transformations.
d601 1
a601 1
  // Defaults for auxiliary coordinate system information.
d664 1
a664 1
  // No additional auxiliary coordinate system information.
d667 1
a667 1
  // Tabular parameters.
d673 1
a673 1
  // Reset derived values.
d687 1
a687 1
//----------------------------------------------------------------------------
d699 1
a699 1
  // Check inputs.
d703 1
a703 1
  // Allocate memory if required.
d706 1
a706 1
      // In case the caller fiddled with it.
d728 1
a728 1
//----------------------------------------------------------------------------
d756 1
a756 1
  // N.B. we do not rely on the wcsprm struct having been set up.
d769 1
a769 1
  // Allocate enough temporary storage to hold either axes[] xor map[].
d776 1
a776 1
    // Construct an index array.
d787 1
a787 1
  // So that we don't try to free uninitialized pointers on cleanup.
d797 1
a797 1
      // Subimage extraction by type.
d818 1
a818 1
        // Find the last non-blank character.
d877 1
a877 1
        // This axis is wanted, but has it already been added?
d887 1
a887 1
      // Check that the requested axis has not already been added.
d896 1
a896 1
      // Graft on a new axis.
d906 1
a906 1
    // Zero out this struct.
d916 5
a920 5
  // Construct the inverse axis map (i is 0-relative, j is 1-relative):
  // axes[i] == j means that output axis i+1 comes from input axis j,
  // axes[i] == 0 means to create a new axis,
  //  map[i] == j means that input axis i+1 goes to output axis j,
  //  map[i] == 0 means that input axis i+1 is not used.
d933 2
a934 2
  // Check that the subimage coordinate system is separable.  First check
  // non-zero, off-diagonal elements of the linear transformation matrix.
d947 2
a948 2
  // Now check for distortions that depend on other axes.  As the disprm
  // struct may not have been initialized, we must parse the dpkey entries.
d962 1
a962 1
        // Axis numbers in axmap[] are 0-relative.
d970 1
a970 1
          // Thorough error checking will be done later by disset().
d997 1
a997 1
            // Make room for an additional DPja.AXIS.j record.
d1002 1
a1002 1
            // Distortion depends on an axis excluded from the subimage.
d1014 1
a1014 1
  // Number of PVi_ma records in the subimage.
d1023 1
a1023 1
  // Number of PSi_ma records in the subimage.
d1032 1
a1032 1
  // Initialize the destination.
d1049 1
a1049 1
      // Also inits disdst.
d1060 1
a1060 1
  // Linear transformation.
d1090 1
a1090 1
  // Coordinate reference value.
d1100 1
a1100 1
  // Coordinate units and type.
d1109 1
a1109 1
  // Celestial and spectral transformation parameters.
d1115 1
a1115 1
  // Parameter values.
d1120 1
a1120 1
      // i == 0 is a special code that means "the latitude axis".
d1143 1
a1143 1
  // Alternate linear transformations.
d1152 2
a1153 2
        // A new axis is being created where CDi_ja was present in the input
        // header, so override the default value of 0 set by wcsinit().
d1171 1
a1171 1
  // Auxiliary coordinate system information.
d1239 1
a1239 1
  // Additional auxiliary coordinate system information.
d1256 1
a1256 1
  // Coordinate lookup tables; only copy what's needed.
d1259 1
a1259 1
    // Is this table wanted?
d1271 1
a1271 1
    // Allocate memory for tabprm structs.
d1300 1
a1300 1
  // Distortion parameters (in linprm).
d1313 1
a1313 1
      // Distortion type and maximum distortion (but not total distortion).
d1322 1
a1322 1
      // DPja or DQia keyvalues.
d1328 1
a1328 1
        // Determine the axis mapping.
d1355 1
a1355 1
        // Copy the DPja or DQia keyvalues.
d1364 1
a1364 1
            // Skip it, we will create our own later.
d1419 1
a1419 1
//----------------------------------------------------------------------------
d1448 1
a1448 1
    // Don't compare crpix.
d1476 1
a1476 1
  // Compare pv cards, which may not be in the same order
d1487 1
a1487 1
    // We didn't find a match, so they are not equal
d1493 1
a1493 1
  // Compare ps cards, which may not be in the same order
d1504 1
a1504 1
    // We didn't find a match, so they are not equal
d1568 1
a1568 1
    // Compare additional auxiliary parameters.
d1582 1
a1582 1
  // Compare tabular parameters
d1600 1
a1600 1
//----------------------------------------------------------------------------
d1613 1
a1613 1
    // Optionally allocated by wcsinit() for given parameters.
d1615 1
a1615 1
      // Start by cleaning the slate.
d1637 1
a1637 1
      // Now release the memory.
d1655 1
a1655 1
      // May have been allocated by wcspih() or wcssub().
d1658 1
a1658 1
      // Allocated unconditionally by wcstab().
d1669 1
a1669 1
    // Allocated unconditionally by wcsset().
d1716 1
a1716 1
//----------------------------------------------------------------------------
d1758 1
a1758 1
  // Linear transformation.
d1769 1
a1769 1
  // Coordinate increment at reference point.
d1777 1
a1777 1
  // Coordinate value at reference point.
d1785 1
a1785 1
  // Coordinate units and type.
d1796 1
a1796 1
  // Celestial and spectral transformation parameters.
d1806 1
a1806 1
  // Parameter values.
d1822 1
a1822 1
  // Alternate linear transformations.
d1849 1
a1849 1
  // Auxiliary coordinate system information.
d1993 1
a1993 1
  // Additional auxiliary coordinate system information.
d2012 1
a2012 1
  // Derived values.
d2035 1
a2035 1
  // Memory management.
d2097 1
a2097 1
  // Tabular transformation parameters.
d2125 1
a2125 1
  // Linear transformation parameters.
d2130 1
a2130 1
  // Celestial transformation parameters.
d2135 1
a2135 1
  // Spectral transformation parameters.
d2143 1
a2143 1
//----------------------------------------------------------------------------
d2166 1
a2166 1
//----------------------------------------------------------------------------
d2184 1
a2184 1
//----------------------------------------------------------------------------
d2207 1
a2207 1
  // Determine axis types from CTYPEia.
d2212 1
a2212 1
  // Convert to canonical units.
d2224 1
a2224 1
  // Non-linear celestial axes present?
d2228 1
a2228 1
    // CRVALia, LONPOLEa, and LATPOLEa keyvalues.
d2234 1
a2234 1
    // Do alias translation for TPU/TPV before dealing with PVi_ma.
d2239 1
a2239 1
      // Translate the PV parameters.
d2246 1
a2246 1
      // Attach it to linprm.  Also inits it.
d2249 1
a2249 1
        // Prior distortion.
d2253 1
a2253 1
        // Sequent distortion.
d2258 1
a2258 1
      // Yes, the distortion type is "TPV" even for TPU.
d2262 1
a2262 1
      // Keep the keywords in axis-order to aid debugging.
d2272 1
a2272 1
      // Copy distortion parameters for the longitude axis.
d2280 1
a2280 1
      // Now the latitude axis.
d2294 1
a2294 1
      // Erase PVi_ma associated with the celestial axes.
d2310 2
a2311 2
      // As the PVi_ma have now been erased, ctype must be reset to prevent
      // this translation from re-occurring if wcsset() is called again.
d2316 1
a2316 1
      // The WAT distortion should already have been encoded in disseq.
d2322 1
a2322 1
      // The WAT distortion should already have been encoded in disseq.
d2328 1
a2328 1
    // PVi_ma keyvalues.
d2331 1
a2331 1
        // From a PROJPn keyword.
d2339 1
a2339 1
        // PVi_ma associated with latitude axis.
d2345 1
a2345 1
        // PVi_ma associated with longitude axis.
d2357 1
a2357 1
          // If present, overrides LONPOLEa.
d2361 1
a2361 1
          // If present, overrides LATPOLEa.
d2373 1
a2373 1
    // Do simple alias translations.
d2381 1
a2381 1
      // Convert NCP to SIN.
d2392 1
a2392 1
    // Initialize the celestial transformation routines.
d2398 1
a2398 1
    // Update LONPOLE, LATPOLE, and PVi_ma keyvalues.
d2426 1
a2426 1
  // Non-linear spectral axis present?
d2436 1
a2436 1
    // CRVALia, RESTFRQa, and RESTWAVa keyvalues.
d2441 1
a2441 1
    // PVi_ma keyvalues.
d2447 1
a2447 1
        // PVi_ma associated with grism axis.
d2454 1
a2454 1
    // Initialize the spectral transformation routines.
d2461 1
a2461 1
  // Tabular axes present?
d2469 1
a2469 1
  // Initialize the linear transformation.
d2475 1
a2475 1
      // Copy CDi_ja to PCi_ja and reset CDELTia.
d2485 1
a2485 1
      // Construct PCi_ja from CROTAia.
d2511 1
a2511 1
  // Set defaults for radesys and equinox for equatorial or ecliptic.
d2526 1
a2526 1
      // Equinox is not applicable for these coordinate systems.
d2539 1
a2539 1
    // No celestial axes, ensure that radesys and equinox are unset.
d2545 1
a2545 1
  // Strip off trailing blanks and null-fill auxiliary string members.
d2569 1
a2569 1
  // MJDREF defaults to zero if no reference date keywords were defined.
d2584 1
a2584 1
// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
d2602 1
a2602 1
  // Parse the CTYPEia keyvalues.
d2620 1
a2620 1
    // Null fill.
d2626 1
a2626 1
    // Check for early Paper IV syntax (e.g. '-SIP' used by Spitzer).
d2628 1
a2628 1
      // Excise the "4-3-3" or "8-3"-form distortion code.
d2631 1
a2631 1
      // Remove trailing dashes from "8-3"-form codes.
d2638 1
a2638 1
    // Logarithmic or tabular axis?
d2641 1
a2641 1
      // Logarithmic axis.
d2645 1
a2645 1
      // Tabular axis.
d2650 1
a2650 1
      // Could have -LOG or -TAB with celestial or spectral types.
d2653 1
a2653 1
      // Take care of things like 'FREQ-LOG' or 'RA---TAB'.
d2660 1
a2660 1
    // Translate AIPS spectral types for spctyp().
d2666 1
a2666 1
    // Process linear axes.
d2668 1
a2668 1
      // Identify Stokes, celestial and spectral types.
d2670 1
a2670 1
        // STOKES axis.
d2676 1
a2676 1
        // Longitude axis.
d2686 1
a2686 1
        // Latitude axis.
d2694 1
a2694 1
        // CUBEFACE axis.
d2699 1
a2699 1
          // Multiple CUBEFACE axes!
d2706 1
a2706 1
        // Spectral axis.
d2715 1
a2715 1
    // CTYPEia is in "4-3" form; is it a recognized spectral type?
d2717 1
a2717 1
      // Non-linear spectral axis found.
d2720 1
a2720 1
      // Check uniqueness.
d2733 1
a2733 1
    // Is it a recognized celestial projection?
d2739 1
a2739 1
      // Not a standard projection code, maybe it's an alias.
d2745 1
a2745 1
        // Not a recognized algorithm code of any type.
d2753 1
a2753 1
    // Parse the celestial axis type.
d2756 1
a2756 1
      // The first of the two celestial axes.
d2796 1
a2796 1
        // Unrecognized celestial type.
d2809 1
a2809 1
      // Looking for the complementary celestial axis.
d2813 1
a2813 1
        // Inconsistent projection types.
d2826 1
a2826 1
  // Do we have a complementary pair of celestial axes?
d2828 1
a2828 1
    // Unmatched celestial axis.
d2835 1
a2835 1
  // Table group numbers.
d2838 1
a2838 1
      // Get image axis number.
d2853 1
a2853 1
// : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :
d2870 1
a2870 1
    // Use types set by wcs_types().
d2873 1
a2873 1
      // Celestial axis.
d2878 1
a2878 1
      // Spectral axis.
d2888 1
a2888 1
    // Tabular axis, CDELTia and CRVALia relate to indices.
d2922 1
a2922 1
//----------------------------------------------------------------------------
d2946 1
a2946 1
  // Initialize if required.
d2954 1
a2954 1
  // Sanity check.
d2961 1
a2961 1
  // Apply pixel-to-world linear transformation.
d2966 1
a2966 1
  // Initialize status vectors.
d2975 1
a2975 1
  // Convert intermediate world coordinates to world coordinates.
d2977 1
a2977 1
    // Extract the second digit of the axis type code.
d2981 1
a2981 1
      // Linear or quantized coordinate axis.
d2992 1
a2992 1
      // Convert celestial coordinates; do we have a CUBEFACE axis?
d2994 1
a2994 1
        // Separation between faces.
d3001 1
a3001 1
        // Lay out faces in a plane.
d3042 1
a3042 1
      // Check for constant x and/or y.
d3054 1
a3054 1
      // Transform projection plane coordinates to celestial coordinates.
d3066 1
a3066 1
      // If x and y were both constant, replicate values.
d3081 1
a3081 1
      // Check for constant x.
d3089 1
a3089 1
        // Spectral coordinates.
d3099 1
a3099 1
        // Logarithmic coordinates.
d3110 1
a3110 1
      // If x was constant, replicate values.
d3123 1
a3123 1
  // Do tabular coordinates.
d3144 1
a3144 1
  // Zero the unused world coordinate elements.
d3155 1
a3155 1
//----------------------------------------------------------------------------
d3181 1
a3181 1
  // Initialize if required.
d3189 1
a3189 1
  // Sanity check.
d3195 1
a3195 1
  // Initialize status vectors.
d3205 1
a3205 1
  // Convert world coordinates to intermediate world coordinates.
d3207 1
a3207 1
    // Extract the second digit of the axis type code.
d3211 1
a3211 1
      // Linear or quantized coordinate axis.
d3222 1
a3222 1
      // Celestial coordinates; check for constant lng and/or lat.
d3234 1
a3234 1
      // Transform celestial coordinates to projection plane coordinates.
d3246 1
a3246 1
      // If lng and lat were both constant, replicate values.
d3260 1
a3260 1
      // Do we have a CUBEFACE axis?
d3262 1
a3262 1
        // Separation between faces.
d3269 1
a3269 1
        // Stack faces in a cube.
d3296 1
a3296 1
      // Check for constancy.
d3304 1
a3304 1
        // Spectral coordinates.
d3314 1
a3314 1
        // Logarithmic coordinates.
d3325 1
a3325 1
      // If constant, replicate values.
d3338 1
a3338 1
  // Do tabular coordinates.
d3359 1
a3359 1
  // Zero the unused intermediate world coordinate elements.
d3366 1
a3366 1
  // Apply world-to-pixel linear transformation.
d3377 1
a3377 1
//----------------------------------------------------------------------------
d3411 1
a3411 1
  // Initialize if required.
d3423 1
a3423 1
  // Check vspan.
d3428 1
a3428 1
    // Swap them.
d3433 1
a3433 1
  // Check vstep.
d3440 1
a3440 1
  // Check viter.
d3448 1
a3448 1
  // Given pixel element.
d3451 1
a3451 1
  // Iterate on the step size.
d3455 1
a3455 1
    // Iterate on the sky coordinate between the specified range.
d3457 1
a3457 1
      // Celestial longitude is given.
d3459 1
a3459 1
      // Check whether the solution interval is a crossing interval.
d3491 1
a3491 1
      // Check for a crossing point.
d3501 1
a3501 1
        // Refine the solution interval.
d3515 1
a3515 1
          // Check for a solution.
d3519 1
a3519 1
          // Record the point of closest approach.
d3525 1
a3525 1
          // Check for a crossing point.
d3532 1
a3532 1
          // Advance to the next subinterval.
d3538 1
a3538 1
          // A crossing point was found.
d3540 1
a3540 1
            // Use regula falsi division of the interval.
d3559 1
a3559 1
            // Check for a solution.
d3565 1
a3565 1
              // An artifact of numerical imprecision.
d3568 1
a3568 1
              // Must be a discontinuity.
d3572 1
a3572 1
            // Record the point of closest approach.
d3587 1
a3587 1
          // No convergence, must have been a discontinuity.
d3594 1
a3594 1
          // No crossing point; look for a tangent point.
d3674 1
a3674 1
      // Celestial latitude is given.
d3676 1
a3676 1
      // Check whether the solution interval is a crossing interval.
d3707 1
a3707 1
      // Check for a crossing point.
d3717 1
a3717 1
        // Refine the solution interval.
d3731 1
a3731 1
          // Check for a solution.
d3735 1
a3735 1
          // Record the point of closest approach.
d3741 1
a3741 1
          // Check for a crossing point.
d3748 1
a3748 1
          // Advance to the next subinterval.
d3754 1
a3754 1
          // A crossing point was found.
d3756 1
a3756 1
            // Use regula falsi division of the interval.
d3775 1
a3775 1
            // Check for a solution.
d3781 1
a3781 1
              // An artifact of numerical imprecision.
d3784 1
a3784 1
              // Must be a discontinuity.
d3788 1
a3788 1
            // Record the point of closest approach.
d3803 1
a3803 1
          // No convergence, must have been a discontinuity.
d3810 1
a3810 1
          // No crossing point; look for a tangent point.
d3892 1
a3892 1
  // Set cel0 to the unity transformation.
d3900 1
a3900 1
  // No convergence, check for aberrant behaviour at a native pole.
d3903 1
a3903 1
    // Could the celestial coordinate element map to a native pole?
d3922 1
a3922 1
    // Is there a solution for the given pixel coordinate element?
d3926 1
a3926 1
    // Feed native coordinates to wcss2p() with cel0 set to unity.
d3940 1
a3940 1
    // Check for a solution.
d3942 1
a3942 1
      // Recall saved world coordinates.
d3948 1
a3948 1
    // Search for a crossing interval.
d3964 1
a3964 1
      // Check for a solution.
d3967 1
a3967 1
        // Recall saved world coordinates.
d3973 1
a3973 1
      // Is it a crossing interval?
d3981 1
a3981 1
      // Use regula falsi division of the interval.
d4001 1
a4001 1
      // Check for a solution.
d4005 1
a4005 1
        // Recall saved world coordinates.
d4022 1
a4022 1
  // No solution.
d4026 1
a4026 1
//----------------------------------------------------------------------------
d4040 1
a4040 1
  // Initialize if required.
d4050 1
a4050 1
      // Look for a linear spectral axis.
d4058 1
a4058 1
        // No spectral axis.
d4067 1
a4067 1
  // Translate the spectral axis.
d4075 1
a4075 1
  // Translate keyvalues.
d4082 1
a4082 1
  // This keeps things tidy if the spectral axis is linear.
d4089 1
a4089 1
//----------------------------------------------------------------------------
@


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: wcs.c,v 7.3.1.2 2020/08/17 11:19:09 mcalabre Exp mcalabre $
@


7.3.1.4
log
@In wcs_units(), on error return from wcsunitse(), do not attempt to set an
error message, via wcserr_set(), if wcserr messaging is not enabled - the
attempt to dereference uniterr (== 0x0) produced a segv.
@
text
@d24 1
a24 1
  $Id: wcs.c,v 7.3.1.3 2021/01/19 14:09:10 mcalabre Exp mcalabre $
d2896 3
a2898 6
        if (uniterr) {
          // uniterr will not be set if wcserr is not enabled.
          wcserr_set(WCSERR_SET(WCSERR_BAD_COORD_TRANS),
            "In CUNIT%d%.1s: %s", i+1, (*wcs->alt)?wcs->alt:"", uniterr->msg);
          free(uniterr);
        }
@


7.3.1.5
log
@Removed my email address from the copyright notice.
@
text
@d20 2
d24 1
a24 1
  $Id: wcs.c,v 7.3.1.4 2021/01/28 11:36:54 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: wcs.c,v 7.1.1.2 2020/02/26 08:15:14 mcalabre Exp mcalabre $
@


7.2.1.1
log
@WCSLIB 7.2 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 6.4.1.5 2019/12/31 03:28:03 mcalabre Exp mcalabre $
d742 1
a742 1
  int  axis, axmap[10], cubeface, dealloc, dummy, i, idp, itab, *itmp = 0x0,
d963 1
a963 1
        for (jhat = 0; jhat < 10; jhat++) {
d986 1
a986 1
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat || 10 < Nhat) {
d1263 1
a1263 1
      if (map[i-1]) {
d1287 1
a1287 1
      if (map[i-1]) {
d1329 1
a1329 1
        for (jhat = 0; jhat < 10; jhat++) {
@


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


7.1.1.2
log
@In wcssub(), fixed a longstanding bug relating to handling coordinate
lookup tables.  Also increased the number of coordinate axes handled
from 10 to 32.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 7.1.1.1 2019/12/31 13:28:19 mcalabre Exp mcalabre $
d742 1
a742 1
  int  axis, axmap[32], cubeface, dealloc, dummy, i, idp, itab, *itmp = 0x0,
d963 1
a963 1
        for (jhat = 0; jhat < 32; jhat++) {
d986 1
a986 1
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat || 32 < Nhat) {
d1263 1
a1263 1
      if (map[i]) {
d1287 1
a1287 1
      if (map[i]) {
d1329 1
a1329 1
        for (jhat = 0; jhat < 32; jhat++) {
@


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: wcs.c,v 6.3.1.1 2019/07/12 07:34:37 mcalabre Exp mcalabre $
d215 1
d664 4
d689 41
d787 2
a788 1
  /* So that we don't try to free an uninitialized pointer on cleanup. */
d1189 4
a1192 4
  strncpy(wcsdst->timesys,  wcssrc->timesys, 72);
  strncpy(wcsdst->trefpos,  wcssrc->trefpos, 72);
  strncpy(wcsdst->trefdir,  wcssrc->trefdir, 72);
  strncpy(wcsdst->plephem,  wcssrc->plephem, 72);
d1239 62
a1300 1
  /* Distortion parameters. */
a1397 44
  /* Coordinate lookup tables; only copy what's needed. */
  wcsdst->ntab = 0;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    /* Is this table wanted? */
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];

      if (map[i-1]) {
        wcsdst->ntab++;
        break;
      }
    }
  }

  if (wcsdst->ntab) {
    /* Allocate memory for tabprm structs. */
    if ((wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm))) == 0x0) {
      wcsdst->ntab = 0;

      status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      goto cleanup;
    }

    wcsdst->m_tab = wcsdst->tab;
  }

  tab = wcsdst->tab;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];

      if (map[i-1]) {
        if ((status = tabcpy(1, wcssrc->tab + itab, tab))) {
          wcserr_set(WCS_ERRMSG(wcs_taberr[status]));
          goto cleanup;
        }

        tab++;
        break;
      }
    }
  }


d1404 6
d1567 13
d1615 1
d1632 2
d1637 1
d1655 3
d1696 2
d1993 10
d2087 3
d2218 4
d2264 1
d2270 1
d2277 1
d2285 1
d2291 1
a2293 2
      dis->ndp = keyp - dis->dp;

d2546 3
a2548 1
  wcsutil_null_fill(4, wcs->alt);
d2568 10
@


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


6.4.1.2
log
@In wcsset(), MJDREF defaults to zero if no reference date keywords were
defined.  wcsset() now also ensures that the number of coordinate axes does
not exceed 32.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 6.4.1.1 2019/08/15 09:31:29 mcalabre Exp mcalabre $
a2112 4
  if (32 < naxis) {
    return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
      "naxis must not exceed 32 (got %d)", naxis);
  }
a2453 10

  /* MJDREF defaults to zero if no reference date keywords were defined. */
  if (wcs->dateref[0] == '\0') {
    if (undefined(wcs->mjdref[0])) {
      wcs->mjdref[0] = 0.0;    
    }
    if (undefined(wcs->mjdref[1])) {
      wcs->mjdref[1] = 0.0;    
    }
  }
@


6.4.1.3
log
@In wcsset(), quell a warning from Microsoft Visual C++ (MSVC) relating to
pointer differencing.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 6.4.1.2 2019/11/29 04:14:40 mcalabre Exp mcalabre $
a2158 1
      dis->ndp = 0;
a2163 1
      dis->ndp += 3;
a2169 1
        dis->ndp++;
a2176 1
      dis->ndp += 3;
a2181 1
        dis->ndp++;
d2183 2
@


6.4.1.4
log
@Added the auxprm struct to hold additional auxiliary coordinate system
information, initially containing five Solar-related keyvalues.  New
function wcsauxi() initialises an auxprm struct.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 6.4.1.3 2019/12/16 04:31:55 mcalabre Exp mcalabre $
a214 1
    wcs->m_aux   = 0x0;
a662 4
  /* No additional auxiliary coordinate system information. */
  wcs->aux  = 0x0;

  /* Tabular parameters. */
a683 41
int wcsauxi(
  int alloc,
  struct wcsprm *wcs)

{
  static const char *function = "wcsauxi";

  struct auxprm *aux;
  struct wcserr **err;

  /* Check inputs. */
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
  err = &(wcs->err);

  /* Allocate memory if required. */
  if (alloc || wcs->aux == 0x0) {
    if (wcs->m_aux) {
      /* In case the caller fiddled with it. */
      wcs->aux = wcs->m_aux;

    } else {
      if ((wcs->aux = malloc(sizeof(struct auxprm))) == 0x0) {
        return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      }

      wcs->m_aux = wcs->aux;
    }
  }

  aux = wcs->aux;
  aux->rsun_ref = UNDEFINED;
  aux->dsun_obs = UNDEFINED;
  aux->crln_obs = UNDEFINED;
  aux->hgln_obs = UNDEFINED;
  aux->hglt_obs = UNDEFINED;

  return 0;
}

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

d741 1
a741 2
  /* So that we don't try to free uninitialized pointers on cleanup. */
  wcsdst->m_aux = 0x0;
d1142 4
a1145 4
  strncpy(wcsdst->timesys, wcssrc->timesys, 72);
  strncpy(wcsdst->trefpos, wcssrc->trefpos, 72);
  strncpy(wcsdst->trefdir, wcssrc->trefdir, 72);
  strncpy(wcsdst->plephem, wcssrc->plephem, 72);
d1192 1
a1192 62
  /* Additional auxiliary coordinate system information. */
  if (wcssrc->aux && !wcsdst->aux) {
    if ((wcsdst->aux = calloc(1, sizeof(struct auxprm))) == 0x0) {
      status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      goto cleanup;
    }

    wcsdst->m_aux = wcsdst->aux;

    wcsdst->aux->rsun_ref = wcssrc->aux->rsun_ref;
    wcsdst->aux->dsun_obs = wcssrc->aux->dsun_obs;
    wcsdst->aux->crln_obs = wcssrc->aux->crln_obs;
    wcsdst->aux->hgln_obs = wcssrc->aux->hgln_obs;
    wcsdst->aux->hglt_obs = wcssrc->aux->hglt_obs;
  }


  /* Coordinate lookup tables; only copy what's needed. */
  wcsdst->ntab = 0;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    /* Is this table wanted? */
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];

      if (map[i-1]) {
        wcsdst->ntab++;
        break;
      }
    }
  }

  if (wcsdst->ntab) {
    /* Allocate memory for tabprm structs. */
    if ((wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm))) == 0x0) {
      wcsdst->ntab = 0;

      status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      goto cleanup;
    }

    wcsdst->m_tab = wcsdst->tab;
  }

  tab = wcsdst->tab;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];

      if (map[i-1]) {
        if ((status = tabcpy(1, wcssrc->tab + itab, tab))) {
          wcserr_set(WCS_ERRMSG(wcs_taberr[status]));
          goto cleanup;
        }

        tab++;
        break;
      }
    }
  }


  /* Distortion parameters (in linprm). */
d1290 44
a1339 6
  if (status && wcsdst->m_aux) {
    free(wcsdst->m_aux);
    wcsdst->aux   = 0x0;
    wcsdst->m_aux = 0x0;
  }

a1496 13

    /* Compare additional auxiliary parameters. */
    if (wcs1->aux && wcs2->aux) {
      if (!wcsutil_Eq(1, tol, &wcs1->aux->rsun_ref, &wcs2->aux->rsun_ref) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->dsun_obs, &wcs2->aux->dsun_obs) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->crln_obs, &wcs2->aux->crln_obs) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->hgln_obs, &wcs2->aux->hgln_obs) ||
          !wcsutil_Eq(1, tol, &wcs1->aux->hglt_obs, &wcs2->aux->hglt_obs)) {
        return 0;
      }
    } else if (wcs1->aux || wcs2->aux) {
      return 0;
    }
a1531 1
      /* Start by cleaning the slate. */
a1547 2

      if (wcs->aux   == wcs->m_aux)   wcs->aux   = 0x0;
a1550 1
      /* Now release the memory. */
a1567 3
      /* May have been allocated by wcspih() or wcssub(). */
      if (wcs->m_aux) free(wcs->m_aux);

a1605 2
  wcs->m_aux    = 0x0;

a1900 10
  /* Additional auxiliary coordinate system information. */
  WCSPRINTF_PTR("        aux: ", wcs->aux, "\n");
  if (wcs->aux) {
    wcsprt_auxd("rsun_ref", wcs->aux->rsun_ref);
    wcsprt_auxd("dsun_obs", wcs->aux->dsun_obs);
    wcsprt_auxd("crln_obs", wcs->aux->crln_obs);
    wcsprt_auxd("hgln_obs", wcs->aux->hgln_obs);
    wcsprt_auxd("hglt_obs", wcs->aux->hglt_obs);
  }

a1984 3
  WCSPRINTF_PTR("      m_aux: ", wcs->m_aux, "");
  if (wcs->m_aux == wcs->aux) wcsprintf("  (= aux)");
  wcsprintf("\n");
d2441 1
a2441 3
  if (wcs->alt[0] == '\0') wcs->alt[0] = ' ';
  memset(wcs->alt+1, '\0', 3);

d2465 1
a2465 1
      wcs->mjdref[0] = 0.0;
d2468 1
a2468 1
      wcs->mjdref[1] = 0.0;
@


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


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: wcs.c,v 6.2.1.5 2019/07/09 11:52:02 mcalabre Exp mcalabre $
@


6.3.1.1
log
@WCSLIB 6.3 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 6.1.1.1 2018/10/19 08:36:15 mcalabre Exp mcalabre $
d168 4
a171 1
  /* Initialize error message handling. */
d173 13
a185 10
  if (wcs->flag != -1) {
    if (wcs->err) free(wcs->err);
    if (wcs->lin.err) free(wcs->lin.err);
    if (wcs->cel.err) free(wcs->cel.err);
    if (wcs->spc.err) free(wcs->spc.err);
  }
  wcs->err = 0x0;
  wcs->lin.err = 0x0;
  wcs->cel.err = 0x0;
  wcs->spc.err = 0x0;
a1578 2
    if (wcs->err) free(wcs->err);

d1613 1
a1613 1
  wcs->err  = 0x0;
d3807 1
a3807 1
      if (wcs->err) free(wcs->err);
d3831 1
a3831 1
        if (wcs->err) free(wcs->err);
d3869 1
a3869 1
        if (wcs->err) free(wcs->err);
@


6.2.1.1
log
@WCSLIB 6.2 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 6.2.1.1 2018/10/20 10:04:15 mcalabre Exp mcalabre $
@


6.2.1.3
log
@In wcsinit(), wcsfree(), and wcsmix(), 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: wcs.c,v 6.2.1.2 2019/05/10 01:56:50 mcalabre Exp mcalabre $
d171 4
a174 4
    wcserr_clear(&(wcs->err));
    wcserr_clear(&(wcs->lin.err));
    wcserr_clear(&(wcs->cel.err));
    wcserr_clear(&(wcs->spc.err));
d1573 1
a1573 1
    wcserr_clear(&(wcs->err));
d3803 1
a3803 1
      wcserr_clear(&(wcs->err));
d3827 1
a3827 1
        wcserr_clear(&(wcs->err));
d3865 1
a3865 1
        wcserr_clear(&(wcs->err));
@


6.2.1.4
log
@Refinements for error message handling in wcsinit() and wcsfree().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 6.2.1.3 2019/07/08 03:34:14 mcalabre Exp mcalabre $
a168 3
  if (wcs->flag == -1) {
    wcs->err = 0x0;
  }
d170 10
a179 1
  wcserr_clear(err);
d1573 2
d1609 1
a1609 1
  wcserr_clear(&(wcs->err));
d3803 1
a3803 1
      wcserr_clear(err);
d3827 1
a3827 1
        wcserr_clear(err);
d3865 1
a3865 1
        wcserr_clear(err);
@


6.2.1.5
log
@In wcsinit(), initialize error message handling in the contained structs in
case of early return due to an error before they can be initialized by their
specialized routines, since wcsperr() assumes their wcserr pointers are
valid.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 6.2.1.4 2019/07/09 08:52:10 mcalabre Exp mcalabre $
d168 1
a168 1
  /* Initialize error message handling... */
a173 12

  /* ...and also in the contained structs in case we have to return due to
     an error before they can be initialized by their specialized routines,
     since wcsperr() assumes their wcserr pointers are valid. */
  if (wcs->flag == -1) {
    wcs->lin.err = 0x0;
    wcs->cel.err = 0x0;
    wcs->spc.err = 0x0;
  }
  wcserr_clear(&(wcs->lin.err));
  wcserr_clear(&(wcs->cel.err));
  wcserr_clear(&(wcs->spc.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: wcs.c,v 5.20.1.2 2018/10/19 06:05:05 mcalabre Exp mcalabre $
@


6.1.1.1
log
@WCSLIB 6.1 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 5.19.1.2 2018/10/05 04:44:10 mcalabre Exp mcalabre $
d39 1
d207 2
d234 3
a236 1
     wcs->csyer == 0x0) {
d495 34
d604 2
d608 15
d624 3
a626 2
  memset(wcs->dateobs, 0, 72);
  wcs->equinox    = UNDEFINED;
d628 13
a640 1
  wcs->mjdobs     = UNDEFINED;
d644 8
a651 3
  memset(wcs->radesys, 0, 72);
  memset(wcs->specsys, 0, 72);
  memset(wcs->ssysobs, 0, 72);
d654 1
a654 1
  memset(wcs->ssyssrc, 0, 72);
a655 1
  memset(wcs->wcsname, 0, 72);
d1129 2
d1134 15
d1150 1
a1150 1
  strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);
d1152 15
a1166 4
  wcsdst->equinox = wcssrc->equinox;

  wcsdst->mjdavg = wcssrc->mjdavg;
  wcsdst->mjdobs = wcssrc->mjdobs;
d1171 3
d1175 5
a1179 3
  strncpy(wcsdst->radesys, wcssrc->radesys, 72);
  strncpy(wcsdst->specsys, wcssrc->specsys, 72);
  strncpy(wcsdst->ssysobs, wcssrc->ssysobs, 72);
d1182 1
a1182 1
  strncpy(wcsdst->ssyssrc, wcssrc->ssyssrc, 72);
a1183 1
  strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);
d1450 39
a1488 14
        strncmp(wcs1->dateavg, wcs2->dateavg, 72) ||
        strncmp(wcs1->dateobs, wcs2->dateobs, 72) ||
        !wcsutil_Eq(1, tol, &wcs1->equinox, &wcs2->equinox) ||
        !wcsutil_Eq(1, tol, &wcs1->mjdavg, &wcs2->mjdavg) ||
        !wcsutil_Eq(1, tol, &wcs1->mjdobs, &wcs2->mjdobs) ||
        !wcsutil_Eq(3, tol, wcs1->obsgeo, wcs2->obsgeo) ||
        strncmp(wcs1->radesys, wcs2->radesys, 72) ||
        strncmp(wcs1->specsys, wcs2->specsys, 72) ||
        strncmp(wcs1->ssysobs, wcs2->ssysobs, 72) ||
        !wcsutil_Eq(1, tol, &wcs1->velosys, &wcs2->velosys) ||
        !wcsutil_Eq(1, tol, &wcs1->zsource, &wcs2->zsource) ||
        strncmp(wcs1->ssyssrc, wcs2->ssyssrc, 72) ||
        !wcsutil_Eq(1, tol, &wcs1->velangl, &wcs2->velangl) ||
        strncmp(wcs1->wcsname, wcs2->wcsname, 72)) {
d1540 2
d1559 2
d1599 2
d1622 18
a1765 6
  if (wcs->wcsname[0] == '\0') {
    wcsprintf("    wcsname: UNDEFINED\n");
  } else {
    wcsprintf("    wcsname: \"%s\"\n", wcs->wcsname);
  }

d1782 1
a1782 1
        wcsprintf("  UNDEFINED   ");
d1795 1
a1795 1
        wcsprintf("  UNDEFINED   ");
d1803 11
a1813 4
  if (wcs->radesys[0] == '\0') {
    wcsprintf("    radesys: UNDEFINED\n");
  } else {
    wcsprintf("    radesys: \"%s\"\n", wcs->radesys);
d1816 11
a1826 4
  if (undefined(wcs->equinox)) {
    wcsprintf("    equinox: UNDEFINED\n");
  } else {
    wcsprintf("    equinox: %9f\n", wcs->equinox);
d1829 1
a1829 5
  if (wcs->specsys[0] == '\0') {
    wcsprintf("    specsys: UNDEFINED\n");
  } else {
    wcsprintf("    specsys: \"%s\"\n", wcs->specsys);
  }
d1831 13
a1843 10
  if (wcs->ssysobs[0] == '\0') {
    wcsprintf("    ssysobs: UNDEFINED\n");
  } else {
    wcsprintf("    ssysobs: \"%s\"\n", wcs->ssysobs);
  }

  if (undefined(wcs->velosys)) {
    wcsprintf("    velosys: UNDEFINED\n");
  } else {
    wcsprintf("    velosys: %9f\n", wcs->velosys);
d1845 2
d1848 20
a1867 11
  if (wcs->ssyssrc[0] == '\0') {
    wcsprintf("    ssyssrc: UNDEFINED\n");
  } else {
    wcsprintf("    ssyssrc: \"%s\"\n", wcs->ssyssrc);
  }

  if (undefined(wcs->zsource)) {
    wcsprintf("    zsource: UNDEFINED\n");
  } else {
    wcsprintf("    zsource: %9f\n", wcs->zsource);
  }
d1872 1
a1872 1
      wcsprintf("UNDEFINED     ");
d1874 9
a1882 1
      wcsprintf("  %#- 11.5g", wcs->obsgeo[i]);
d1887 9
a1895 23
  if (wcs->dateobs[0] == '\0') {
    wcsprintf("    dateobs: UNDEFINED\n");
  } else {
    wcsprintf("    dateobs: \"%s\"\n", wcs->dateobs);
  }

  if (wcs->dateavg[0] == '\0') {
    wcsprintf("    dateavg: UNDEFINED\n");
  } else {
    wcsprintf("    dateavg: \"%s\"\n", wcs->dateavg);
  }

  if (undefined(wcs->mjdobs)) {
    wcsprintf("     mjdobs: UNDEFINED\n");
  } else {
    wcsprintf("     mjdobs: %9f\n", wcs->mjdobs);
  }

  if (undefined(wcs->mjdavg)) {
    wcsprintf("     mjdavg: UNDEFINED\n");
  } else {
    wcsprintf("     mjdavg: %9f\n", wcs->mjdavg);
  }
d1975 6
d2214 5
a2221 5
      if (i == -1) {
        /* From a PROJPn keyword. */
        i = wcs->lat;
      }

a2430 1
  wcsutil_null_fill(72, wcs->wcsname);
d2434 12
a2449 2
  wcsutil_null_fill(72, wcs->dateobs);
  wcsutil_null_fill(72, wcs->dateavg);
@


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


5.20.1.2
log
@Added support for time-related WCS keywords.  Functions affected: wcsinit(),
wcssub(), wcscompare(), wcsfree(), wcsprt(), and wcsset().  Also, in wcsset(),
set the axis number in wcsprm::pv for translations of PROJPn - needed by
wcshdo().  Need to include wtbarr.h now to get the definition of the wtbarr
struct as it has been moved out of wcs.h.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.20.1.1 2018/10/05 05:33:33 mcalabre Exp mcalabre $
a38 1
#include "wtbarr.h"
a205 2
    wcs->m_czphs = 0x0;
    wcs->m_cperi = 0x0;
d231 1
a231 3
     wcs->csyer == 0x0 ||
     wcs->czphs == 0x0 ||
     wcs->cperi == 0x0) {
a489 34

    if (alloc || wcs->czphs == 0x0) {
      if (wcs->m_czphs) {
        /* In case the caller fiddled with it. */
        wcs->czphs = wcs->m_czphs;

      } else {
        if ((wcs->czphs = calloc(naxis, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_czphs = wcs->czphs;
      }
    }

    if (alloc || wcs->cperi == 0x0) {
      if (wcs->m_cperi) {
        /* In case the caller fiddled with it. */
        wcs->cperi = wcs->m_cperi;

      } else {
        if ((wcs->cperi = calloc(naxis, sizeof(double))) == 0x0) {
          wcsfree(wcs);
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cperi = wcs->cperi;
      }
    }
a564 2
    wcs->czphs[i] = UNDEFINED;
    wcs->cperi[i] = UNDEFINED;
d567 1
a567 13
  memset(wcs->wcsname, 0, 72);

  memset(wcs->timesys,  0, 72);
  memset(wcs->trefpos,  0, 72);
  memset(wcs->trefdir,  0, 72);
  memset(wcs->plephem,  0, 72);

  memset(wcs->timeunit, 0, 72);
  memset(wcs->dateref,  0, 72);
  wcs->mjdref[0]  = UNDEFINED;
  wcs->mjdref[1]  = UNDEFINED;
  wcs->timeoffs   = UNDEFINED;

d569 2
a570 3
  memset(wcs->datebeg, 0, 72);
  memset(wcs->dateavg, 0, 72);
  memset(wcs->dateend, 0, 72);
a571 15
  wcs->mjdbeg     = UNDEFINED;
  wcs->mjdavg     = UNDEFINED;
  wcs->mjdend     = UNDEFINED;
  wcs->jepoch     = UNDEFINED;
  wcs->bepoch     = UNDEFINED;
  wcs->tstart     = UNDEFINED;
  wcs->tstop      = UNDEFINED;
  wcs->xposure    = UNDEFINED;
  wcs->telapse    = UNDEFINED;

  wcs->timsyer    = UNDEFINED;
  wcs->timrder    = UNDEFINED;
  wcs->timedel    = UNDEFINED;
  wcs->timepixr   = UNDEFINED;

d575 3
a577 8
  wcs->obsgeo[3]  = UNDEFINED;
  wcs->obsgeo[4]  = UNDEFINED;
  wcs->obsgeo[5]  = UNDEFINED;
  memset(wcs->obsorbit, 0, 72);
  memset(wcs->radesys,  0, 72);
  wcs->equinox    = UNDEFINED;
  memset(wcs->specsys,  0, 72);
  memset(wcs->ssysobs,  0, 72);
d580 1
a580 1
  memset(wcs->ssyssrc,  0, 72);
d582 1
a1055 2
      wcsdst->czphs[i] = wcssrc->czphs[k];
      wcsdst->cperi[i] = wcssrc->cperi[k];
d1059 2
a1060 1
  strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);
d1062 1
a1062 10
  strncpy(wcsdst->timesys,  wcssrc->timesys, 72);
  strncpy(wcsdst->trefpos,  wcssrc->trefpos, 72);
  strncpy(wcsdst->trefdir,  wcssrc->trefdir, 72);
  strncpy(wcsdst->plephem,  wcssrc->plephem, 72);

  strncpy(wcsdst->timeunit, wcssrc->timeunit, 72);
  strncpy(wcsdst->dateref,  wcssrc->dateref, 72);
  wcsdst->mjdref[0] = wcssrc->mjdref[0];
  wcsdst->mjdref[1] = wcssrc->mjdref[1];
  wcsdst->timeoffs  = wcssrc->timeoffs;
d1064 2
a1065 20
  strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);
  strncpy(wcsdst->datebeg, wcssrc->datebeg, 72);
  strncpy(wcsdst->dateavg, wcssrc->dateavg, 72);
  strncpy(wcsdst->dateend, wcssrc->dateend, 72);

  wcsdst->mjdobs  = wcssrc->mjdobs;
  wcsdst->mjdbeg  = wcssrc->mjdbeg;
  wcsdst->mjdavg  = wcssrc->mjdavg;
  wcsdst->mjdend  = wcssrc->mjdend;
  wcsdst->jepoch  = wcssrc->jepoch;
  wcsdst->bepoch  = wcssrc->bepoch;
  wcsdst->tstart  = wcssrc->tstart;
  wcsdst->tstop   = wcssrc->tstop;
  wcsdst->xposure = wcssrc->xposure;
  wcsdst->telapse = wcssrc->telapse;

  wcsdst->timsyer  = wcssrc->timsyer;
  wcsdst->timrder  = wcssrc->timrder;
  wcsdst->timedel  = wcssrc->timedel;
  wcsdst->timepixr = wcssrc->timepixr;
a1069 3
  wcsdst->obsgeo[3] = wcssrc->obsgeo[3];
  wcsdst->obsgeo[4] = wcssrc->obsgeo[4];
  wcsdst->obsgeo[5] = wcssrc->obsgeo[5];
d1071 3
a1073 5
  strncpy(wcsdst->obsorbit, wcssrc->obsorbit, 72);
  strncpy(wcsdst->radesys,  wcssrc->radesys, 72);
  wcsdst->equinox = wcssrc->equinox;
  strncpy(wcsdst->specsys,  wcssrc->specsys, 72);
  strncpy(wcsdst->ssysobs,  wcssrc->ssysobs, 72);
d1076 1
a1076 1
  strncpy(wcsdst->ssyssrc,  wcssrc->ssyssrc, 72);
d1078 1
d1345 14
a1358 39
        !wcsutil_Eq(naxis, tol, wcs1->czphs, wcs2->czphs) ||
        !wcsutil_Eq(naxis, tol, wcs1->cperi, wcs2->cperi) ||
        strncmp(wcs1->wcsname,  wcs2->wcsname,  72) ||
        strncmp(wcs1->timesys,  wcs2->timesys,  72) ||
        strncmp(wcs1->trefpos,  wcs2->trefpos,  72) ||
        strncmp(wcs1->trefdir,  wcs2->trefdir,  72) ||
        strncmp(wcs1->plephem,  wcs2->plephem,  72) ||
        strncmp(wcs1->timeunit, wcs2->timeunit, 72) ||
        strncmp(wcs1->dateref,  wcs2->dateref,  72) ||
        !wcsutil_Eq(2, tol,  wcs1->mjdref,    wcs2->mjdref)   ||
        !wcsutil_Eq(1, tol, &wcs1->timeoffs, &wcs2->timeoffs) ||
        strncmp(wcs1->dateobs,  wcs2->dateobs, 72) ||
        strncmp(wcs1->datebeg,  wcs2->datebeg, 72) ||
        strncmp(wcs1->dateavg,  wcs2->dateavg, 72) ||
        strncmp(wcs1->dateend,  wcs2->dateend, 72) ||
        !wcsutil_Eq(1, tol, &wcs1->mjdobs,   &wcs2->mjdobs)   ||
        !wcsutil_Eq(1, tol, &wcs1->mjdbeg,   &wcs2->mjdbeg)   ||
        !wcsutil_Eq(1, tol, &wcs1->mjdavg,   &wcs2->mjdavg)   ||
        !wcsutil_Eq(1, tol, &wcs1->mjdend,   &wcs2->mjdend)   ||
        !wcsutil_Eq(1, tol, &wcs1->jepoch,   &wcs2->jepoch)   ||
        !wcsutil_Eq(1, tol, &wcs1->bepoch,   &wcs2->bepoch)   ||
        !wcsutil_Eq(1, tol, &wcs1->tstart,   &wcs2->tstart)   ||
        !wcsutil_Eq(1, tol, &wcs1->tstop,    &wcs2->tstop)    ||
        !wcsutil_Eq(1, tol, &wcs1->xposure,  &wcs2->xposure)  ||
        !wcsutil_Eq(1, tol, &wcs1->telapse,  &wcs2->telapse)  ||
        !wcsutil_Eq(1, tol, &wcs1->timsyer,  &wcs2->timsyer)  ||
        !wcsutil_Eq(1, tol, &wcs1->timrder,  &wcs2->timrder)  ||
        !wcsutil_Eq(1, tol, &wcs1->timedel,  &wcs2->timedel)  ||
        !wcsutil_Eq(1, tol, &wcs1->timepixr, &wcs2->timepixr) ||
        !wcsutil_Eq(6, tol,  wcs1->obsgeo,    wcs2->obsgeo)   ||
        strncmp(wcs1->obsorbit, wcs2->obsorbit, 72) ||
        strncmp(wcs1->radesys,  wcs2->radesys,  72) ||
        !wcsutil_Eq(1, tol, &wcs1->equinox,  &wcs2->equinox)  ||
        strncmp(wcs1->specsys,  wcs2->specsys,  72) ||
        strncmp(wcs1->ssysobs,  wcs2->ssysobs,  72) ||
        !wcsutil_Eq(1, tol, &wcs1->velosys,  &wcs2->velosys)  ||
        !wcsutil_Eq(1, tol, &wcs1->zsource,  &wcs2->zsource)  ||
        strncmp(wcs1->ssyssrc,  wcs2->ssyssrc,  72) ||
        !wcsutil_Eq(1, tol, &wcs1->velangl,  &wcs2->velangl)) {
a1409 2
      if (wcs->czphs == wcs->m_czphs) wcs->czphs = 0x0;
      if (wcs->cperi == wcs->m_cperi) wcs->cperi = 0x0;
a1426 2
      if (wcs->m_czphs)  free(wcs->m_czphs);
      if (wcs->m_cperi)  free(wcs->m_cperi);
a1464 2
  wcs->m_czphs  = 0x0;
  wcs->m_cperi  = 0x0;
a1485 18
static void wcsprt_auxc(const char *name, const char *value)
{
  if (value[0] == '\0') {
    wcsprintf("   %s: UNDEFINED\n", name);
  } else {
    wcsprintf("   %s: \"%s\"\n", name, value);
  }
}

static void wcsprt_auxd(const char *name, double value)
{
  if (undefined(value)) {
    wcsprintf("   %s: UNDEFINED\n", name);
  } else {
    wcsprintf("   %s:  %15.9f\n", name, value);
  }
}

d1612 6
d1634 1
a1634 1
        wcsprintf("    UNDEFINED");
d1647 1
a1647 1
        wcsprintf("    UNDEFINED");
d1655 16
a1670 11
  WCSPRINTF_PTR("      czphs: ", wcs->czphs, "\n");
  if (wcs->czphs) {
    wcsprintf("           ");
    for (i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->czphs[i])) {
        wcsprintf("    UNDEFINED");
      } else {
        wcsprintf("  %#- 11.5g", wcs->czphs[i]);
      }
    }
    wcsprintf("\n");
d1673 4
a1676 11
  WCSPRINTF_PTR("      cperi: ", wcs->cperi, "\n");
  if (wcs->cperi) {
    wcsprintf("           ");
    for (i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->cperi[i])) {
        wcsprintf("    UNDEFINED");
      } else {
        wcsprintf("  %#- 11.5g", wcs->cperi[i]);
      }
    }
    wcsprintf("\n");
d1679 5
a1683 1
  wcsprt_auxc(" wcsname", wcs->wcsname);
d1685 4
a1688 13
  wcsprt_auxc(" timesys", wcs->timesys);
  wcsprt_auxc(" trefpos", wcs->trefpos);
  wcsprt_auxc(" trefdir", wcs->trefdir);
  wcsprt_auxc(" plephem", wcs->plephem);
  wcsprt_auxc("timeunit", wcs->timeunit);
  wcsprt_auxc(" dateref", wcs->dateref);
  wcsprintf("     mjdref: ");
  for (i = 0; i < 2; i++) {
    if (undefined(wcs->mjdref[i])) {
      wcsprintf("       UNDEFINED");
    } else {
      wcsprintf(" %15.9f", wcs->mjdref[i]);
    }
a1689 2
  wcsprintf("\n");
  wcsprt_auxd("timeoffs", wcs->timeoffs);
d1691 5
a1695 20
  wcsprt_auxc(" dateobs", wcs->dateobs);
  wcsprt_auxc(" datebeg", wcs->datebeg);
  wcsprt_auxc(" dateavg", wcs->dateavg);
  wcsprt_auxc(" dateend", wcs->dateend);
  wcsprt_auxd("  mjdobs", wcs->mjdobs);
  wcsprt_auxd("  mjdbeg", wcs->mjdbeg);
  wcsprt_auxd("  mjdavg", wcs->mjdavg);
  wcsprt_auxd("  mjdend", wcs->mjdend);
  wcsprt_auxd("  jepoch", wcs->jepoch);
  wcsprt_auxd("  bepoch", wcs->bepoch);
  wcsprt_auxd("  tstart", wcs->tstart);
  wcsprt_auxd("   tstop", wcs->tstop);
  wcsprt_auxd(" xposure", wcs->xposure);
  wcsprt_auxd(" telapse", wcs->telapse);


  wcsprt_auxd(" timsyer", wcs->timsyer);
  wcsprt_auxd(" timrder", wcs->timrder);
  wcsprt_auxd(" timedel", wcs->timedel);
  wcsprt_auxd("timepixr", wcs->timepixr);
d1700 1
a1700 1
      wcsprintf("       UNDEFINED");
d1702 1
a1702 1
      wcsprintf(" %15.6f", wcs->obsgeo[i]);
d1705 18
a1722 7
  wcsprintf("\n             ");
  for (i = 3; i < 6; i++) {
    if (undefined(wcs->obsgeo[i])) {
      wcsprintf("       UNDEFINED");
    } else {
      wcsprintf(" %15.6f", wcs->obsgeo[i]);
    }
a1723 1
  wcsprintf("\n");
d1725 5
a1729 9
  wcsprt_auxc("obsorbit", wcs->obsorbit);
  wcsprt_auxc(" radesys", wcs->radesys);
  wcsprt_auxd(" equinox", wcs->equinox);
  wcsprt_auxc(" specsys", wcs->specsys);
  wcsprt_auxc(" ssysobs", wcs->ssysobs);
  wcsprt_auxd(" velosys", wcs->velosys);
  wcsprt_auxd(" zsource", wcs->zsource);
  wcsprt_auxc(" ssyssrc", wcs->ssyssrc);
  wcsprt_auxd(" velangl", wcs->velangl);
a1808 6
  WCSPRINTF_PTR("    m_czphs: ", wcs->m_czphs, "");
  if (wcs->m_czphs == wcs->czphs) wcsprintf("  (= czphs)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_cperi: ", wcs->m_cperi, "");
  if (wcs->m_cperi == wcs->cperi) wcsprintf("  (= cperi)");
  wcsprintf("\n");
d2042 4
a2045 1
      if (wcs->pv[k].i == 0) {
d2047 1
a2047 1
        wcs->pv[k].i = wcs->lat + 1;
a2049 3
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;

d2259 1
a2262 12
  wcsutil_null_fill(72, wcs->wcsname);
  wcsutil_null_fill(72, wcs->timesys);
  wcsutil_null_fill(72, wcs->trefpos);
  wcsutil_null_fill(72, wcs->trefdir);
  wcsutil_null_fill(72, wcs->plephem);
  wcsutil_null_fill(72, wcs->timeunit);
  wcsutil_null_fill(72, wcs->dateref);
  wcsutil_null_fill(72, wcs->dateobs);
  wcsutil_null_fill(72, wcs->datebeg);
  wcsutil_null_fill(72, wcs->dateavg);
  wcsutil_null_fill(72, wcs->dateend);
  wcsutil_null_fill(72, wcs->obsorbit);
d2267 2
@


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: wcs.c,v 5.18.1.3 2018/07/26 14:35:45 mcalabre Exp mcalabre $
d853 1
a853 1
            Nhat = wcsutil_dpkey_int(dpsrc);
d856 1
a856 1
            axmap[jhat-1] = wcsutil_dpkey_int(dpsrc) - 1;
d1123 1
a1123 1
            Nhat = wcsutil_dpkey_int(dpsrc);
d1126 1
a1126 1
            axmap[jhat-1] = wcsutil_dpkey_int(dpsrc) - 1;
@


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


5.19.1.2
log
@wcsutil_dpkey_int() -> dpkeyi(), wcsutil_dpkey_double() -> dpkeyd().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.19.1.1 2018/07/26 15:41:40 mcalabre Exp mcalabre $
d853 1
a853 1
            Nhat = dpkeyi(dpsrc);
d856 1
a856 1
            axmap[jhat-1] = dpkeyi(dpsrc) - 1;
d1123 1
a1123 1
            Nhat = dpkeyi(dpsrc);
d1126 1
a1126 1
            axmap[jhat-1] = dpkeyi(dpsrc) - 1;
@


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: wcs.c,v 5.17.1.5 2018/01/10 08:25:34 mcalabre Exp mcalabre $
d616 1
a616 1
  char *c, ctypei[16], ctmp[8], *fp;
d1114 1
d1117 1
a1117 1
          if (dpsrc->j != j+1) continue;
d1910 1
a1910 1
  char   dpq[8], scode[4], stype[5];
d2286 1
a2286 1
  char ctypei[16], pcode[4], requir[9], scode[4], specsys[9];
@


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


5.18.1.2
log
@In wcssub(), increased the size of the sprintf() output buffer, ctmp[], to
avert -Wformat-overflow warnings from gcc 8.1.0 (with -DFORTIFY_SOURCE=2).
Likewise in wcsset() for dpq[], and wcs_types() for requir[].
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.18.1.1 2018/01/10 08:33:04 mcalabre Exp mcalabre $
d616 1
a616 1
  char *c, ctypei[16], ctmp[16], *fp;
d1909 1
a1909 1
  char   dpq[16], scode[4], stype[5];
d2285 1
a2285 1
  char ctypei[16], pcode[4], requir[16], scode[4], specsys[9];
@


5.18.1.3
log
@In wcssub(), fixed a bug in handling distortion functions on axes with
changed axis number in the subimage.  Uncovered in trying to fix a compiler
warning about possible use of an uninitialized variable
(gcc -Wmaybe-uninitialized).
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.18.1.2 2018/07/24 13:58:12 mcalabre Exp mcalabre $
a1113 1
        Nhat = 0;
d1116 1
a1116 1
          if (dpsrc->j != axes[j]) continue;
@


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: wcs.c,v 5.16.1.2 2017/09/18 08:21:34 mcalabre Exp mcalabre $
d140 15
a154 1
  static const char *function = "wcsini";
d160 1
d163 4
d224 2
a225 2
     (NPVMAX && wcs->pv == 0x0) ||
     (NPSMAX && wcs->ps == 0x0) ||
d236 2
a237 2
        wcs->npvmax  < NPVMAX ||
        wcs->npsmax  < NPSMAX)) {
d349 2
a350 2
        if (NPVMAX) {
          if ((wcs->pv = calloc(NPVMAX, sizeof(struct pvcard))) == 0x0) {
d358 1
a358 1
        wcs->npvmax  = NPVMAX;
d372 2
a373 2
        if (NPSMAX) {
          if ((wcs->ps = calloc(NPSMAX, sizeof(struct pscard))) == 0x0) {
d381 1
a381 1
        wcs->npsmax  = NPSMAX;
d501 1
a501 1
  if ((status = linini(0, naxis, &(wcs->lin)))) {
d780 2
a781 1
    status = wcsini(alloc, 0, wcsdst);
a895 2
  npv = wcsnpv(-1);
  wcsnpv(npvmax);
a904 6
  nps = wcsnps(-1);
  wcsnps(npsmax);

  /* Number of distortion parameters, if any. */
  ndp = disndp(-1);
  disndp(ndpmax);
d907 1
a907 1
  status = wcsini(alloc, *nsub, wcsdst);
d925 1
a925 1
      lindis(m+1, &(wcsdst->lin), disdst);
a928 5
  /* Reset NPVMAX, NPSMAX, and NDPMAX. */
  wcsnpv(npv);
  wcsnps(nps);
  disndp(ndp);

d1027 1
a1027 1
           header, so override the default value of 0 set by wcsini(). */
d1393 1
a1393 1
    /* Optionally allocated by wcsini() for given parameters. */
d1958 1
a1958 2
      ndpmax = disndp(-1);
      disndp(6+wcs->npv);
d1964 1
a1964 1
        lindis(1, wcslin, dis);
d1968 1
a1968 1
        lindis(2, wcslin, dis);
a1970 2

      disndp(ndpmax);
@


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


5.17.1.2
log
@Replace all direct references to NPVMAX with calls to wcsnpv().  Likewise
for NPSMAX and wcsnps().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.17.1.1 2017/09/18 08:45:59 mcalabre Exp mcalabre $
d142 1
a142 1
  int i, j, k, npvmax, npsmax, status;
a147 3
  npvmax = wcsnpv(-1);
  npsmax = wcsnps(-1);

d205 2
a206 2
     (npvmax && wcs->pv == 0x0) ||
     (npsmax && wcs->ps == 0x0) ||
d217 2
a218 2
        wcs->npvmax  < npvmax ||
        wcs->npsmax  < npsmax)) {
d330 2
a331 2
        if (npvmax) {
          if ((wcs->pv = calloc(npvmax, sizeof(struct pvcard))) == 0x0) {
d339 1
a339 1
        wcs->npvmax  = npvmax;
d353 2
a354 2
        if (npsmax) {
          if ((wcs->ps = calloc(npsmax, sizeof(struct pscard))) == 0x0) {
d362 1
a362 1
        wcs->npsmax  = npsmax;
@


5.17.1.3
log
@Added new function wcsinit(), with wcsini() now a thin wrapper over it.
Modified wcssub() to use wcsinit() and lininit() in place of wcsini() and
linini().  Modified wcsset() to use lindist() in place of lindis().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.17.1.2 2017/12/04 04:42:57 mcalabre Exp mcalabre $
d140 1
a140 4
  return wcsinit(alloc, naxis, wcs, -1, -1, -1);
}

/*--------------------------------------------------------------------------*/
d142 1
a142 12
int wcsinit(
  int alloc,
  int naxis,
  struct wcsprm *wcs,
  int npvmax,
  int npsmax,
  int ndpmax)

{
  static const char *function = "wcsinit";

  int i, j, k, status;
a145 1
  /* Check inputs. */
d148 2
a149 3
  if (npvmax < 0) npvmax = wcsnpv(-1);
  if (npsmax < 0) npsmax = wcsnps(-1);

d485 1
a485 1
  if ((status = lininit(0, naxis, &(wcs->lin), ndpmax))) {
d879 2
d890 6
d898 1
a898 1
  status = wcsinit(alloc, *nsub, wcsdst, npvmax, npsmax, ndpmax);
d916 1
a916 1
      lindist(m+1, &(wcsdst->lin), disdst, ndpmax);
d920 5
d1954 2
a1955 1
      ndpmax = 6 + wcs->npv;
d1961 1
a1961 1
        lindist(1, wcslin, dis, ndpmax);
d1965 1
a1965 1
        lindist(2, wcslin, dis, ndpmax);
d1968 2
@


5.17.1.4
log
@In wcssub(), replaced a call to wcsini() with wcsinit(), and fixed a couple
of comments.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.17.1.3 2017/12/05 07:43:16 mcalabre Exp mcalabre $
d780 1
a780 2
    /* Zero out this struct. */
    status = wcsinit(alloc, 0, wcsdst, 0, 0, 0);
d1026 1
a1026 1
           header, so override the default value of 0 set by wcsinit(). */
d1392 1
a1392 1
    /* Optionally allocated by wcsinit() for given parameters. */
@


5.17.1.5
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2018, Mark Calabretta
d25 1
a25 1
  $Id: wcs.c,v 5.17.1.4 2017/12/05 21:15:54 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: wcs.c,v 5.15.1.2 2017/01/15 04:13:33 mcalabre Exp mcalabre $
d816 1
d840 1
a840 1
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat) {
d917 1
a917 1
  /* Reset WCSNPV, WCSNPS, and DISNDP. */
@


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


5.16.1.2
log
@In wcssub(), check that Nhat <= 10, fixed a comment and added another.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.16.1.1 2017/01/15 04:28:59 mcalabre Exp mcalabre $
a815 1
        /* Axis numbers in axmap[] are 0-relative. */
d839 1
a839 1
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat || 10 < Nhat) {
d916 1
a916 1
  /* Reset NPVMAX, NPSMAX, and NDPMAX. */
@


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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.c,v 5.7.1.2 2015/07/08 07:09:44 mcalabre Exp mcalabre $
@


5.8.1.1
log
@WCSLIB 5.8 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 5.6.1.4 2015/06/16 14:16:20 mcalabre Exp mcalabre $
d826 1
a826 1
          if ((fp = strpbrk(dpsrc->field, ".")) == 0x0) continue;
d1110 1
a1110 1
          if ((fp = strpbrk(dpsrc->field, ".")) == 0x0) continue;
d1132 1
a1132 1
          if ((fp = strpbrk(dpsrc->field, ".")) == 0x0) continue;
d1152 1
a1152 1
              fp = strpbrk(dpdst->field, ".") + 1;
d2020 12
d2276 2
a2277 2
  const int  nalias = 4;
  const char aliases [4][4] = {"NCP", "GLS", "TPU", "TPV"};
@


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


5.7.1.2
log
@In wcsset(), replace '-TNX' with '-TAN' in ctype, and likewise '-ZPX' with
'-ZPN'.  In wcssub(), replace calls to strpbrk() with strchr().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.7.1.1 2015/06/29 02:47:24 mcalabre Exp mcalabre $
d826 1
a826 1
          if ((fp = strchr(dpsrc->field, '.')) == 0x0) continue;
d1110 1
a1110 1
          if ((fp = strchr(dpsrc->field, '.')) == 0x0) continue;
d1132 1
a1132 1
          if ((fp = strchr(dpsrc->field, '.')) == 0x0) continue;
d1152 1
a1152 1
              fp = strchr(dpdst->field, '.') + 1;
a2019 12

    } else if (strncmp(wcsprj->code, "TNX", 3) == 0) {
      /* The WAT distortion should already have been encoded in disseq. */
      strcpy(wcsprj->code, "TAN");
      strcpy(wcs->ctype[wcs->lng]+5, "TAN");
      strcpy(wcs->ctype[wcs->lat]+5, "TAN");

    } else if (strncmp(wcsprj->code, "ZPX", 3) == 0) {
      /* The WAT distortion should already have been encoded in disseq. */
      strcpy(wcsprj->code, "ZPN");
      strcpy(wcs->ctype[wcs->lng]+5, "ZPN");
      strcpy(wcs->ctype[wcs->lat]+5, "ZPN");
d2264 2
a2265 2
  const int  nalias = 6;
  const char aliases [6][4] = {"NCP", "GLS", "TPU", "TPV", "TNX", "ZPX"};
@


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: wcs.c,v 5.5.1.1 2015/05/05 13:21:00 mcalabre Exp mcalabre $
a540 1
  memset(wcs->wcsname, 0, 72);
d547 9
a556 1
  wcs->equinox    = UNDEFINED;
d560 1
a561 8
  wcs->zsource    = UNDEFINED;
  wcs->obsgeo[0]  = UNDEFINED;
  wcs->obsgeo[1]  = UNDEFINED;
  wcs->obsgeo[2]  = UNDEFINED;
  memset(wcs->dateobs, 0, 72);
  memset(wcs->dateavg, 0, 72);
  wcs->mjdobs     = UNDEFINED;
  wcs->mjdavg     = UNDEFINED;
d563 1
d596 5
a600 4
  char *c, ctypei[16];
  int  axis, cubeface, dealloc, dummy, i, itab, *itmp = 0x0, j, k, latitude,
       longitude, m, *map, msub, naxis, npv, nps, ntmp, other, spectral,
       status, stokes;
d603 3
a605 1
  struct tabprm *tabp;
d612 1
d625 1
a625 1
  /* Allocate enough temporary storage to hold either axes[] or map[].*/
d770 1
a770 1
  /* Construct the inverse axis map:
d786 3
a788 1
  /* Check that the subimage coordinate system is separable. */
d801 64
a865 3
  /* Initialize the destination. */
  npv = NPVMAX;
  nps = NPSMAX;
d867 4
a870 3
  NPVMAX = 0;
  for (k = 0; k < wcssrc->npv; k++) {
    i = wcssrc->pv[k].i;
d872 1
a872 1
      NPVMAX++;
d875 2
d878 4
a881 3
  NPSMAX = 0;
  for (k = 0; k < wcssrc->nps; k++) {
    i = wcssrc->ps[k].i;
d883 1
a883 1
      NPSMAX++;
d886 2
d889 5
d896 24
a919 2
  NPVMAX = npv;
  NPSMAX = nps;
d939 4
a942 6
    if (axes[i] > 0) {
      for (j = 0; j < *nsub; j++, dstp++) {
        if (axes[j] > 0) {
          k = (axes[i]-1)*naxis + (axes[j]-1);
          *dstp = *(srcp+k);
        }
d983 2
a984 2
  for (k = 0; k < wcssrc->npv; k++) {
    i = wcssrc->pv[k].i;
d987 1
a987 1
      wcsdst->pv[npv] = wcssrc->pv[k];
d991 1
a991 1
      wcsdst->pv[npv] = wcssrc->pv[k];
d999 2
a1000 2
  for (k = 0; k < wcssrc->nps; k++) {
    i = wcssrc->ps[k].i;
d1002 1
a1002 1
      wcsdst->ps[nps] = wcssrc->ps[k];
d1013 8
a1020 6
    if (axes[i] > 0) {
      for (j = 0; j < *nsub; j++, dstp++) {
        if (axes[j] > 0) {
          k = (axes[i]-1)*naxis + (axes[j]-1);
          *dstp = *(srcp+k);
        }
a1040 1
  strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);
d1051 3
a1053 1
  strncpy(wcsdst->radesys, wcssrc->radesys, 72);
d1056 8
d1067 1
d1069 70
a1138 1
  wcsdst->zsource = wcssrc->zsource;
d1140 24
a1163 3
  wcsdst->obsgeo[0] = wcssrc->obsgeo[0];
  wcsdst->obsgeo[1] = wcssrc->obsgeo[1];
  wcsdst->obsgeo[2] = wcssrc->obsgeo[2];
d1165 3
a1167 4
  strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);
  strncpy(wcsdst->dateavg, wcssrc->dateavg, 72);
  wcsdst->mjdobs = wcssrc->mjdobs;
  wcsdst->mjdavg = wcssrc->mjdavg;
d1196 1
a1196 1
  tabp = wcsdst->tab;
d1202 1
a1202 1
        if ((status = tabcpy(1, wcssrc->tab + itab, tabp))) {
d1207 1
a1207 1
        tabp++;
d1902 1
a1902 1
  int i, j, k, m, n, naxis, status;
d1950 1
d1965 2
d2015 5
@


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


5.6.1.2
log
@Augmented wcssub() to handle distortions.  Subsequent testing with tdis2
uncovered bugs in the way wcsprm::pc and wcsprm::cd were copied if a new
axis was added.  In wcsset(), restore the value of NDPMAX after creating
a disprm struct for TPU/TPV.  In wcsini() and wcssub(), changed the order
of initialisation or copying of auxiliary variables to match their order
in wcsprm.  velangl had been omitted from wcssub().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.6.1.1 2015/06/14 07:14:44 mcalabre Exp mcalabre $
d541 1
d548 1
a548 3

  memset(wcs->dateavg, 0, 72);
  memset(wcs->dateobs, 0, 72);
a549 6
  wcs->mjdavg     = UNDEFINED;
  wcs->mjdobs     = UNDEFINED;
  wcs->obsgeo[0]  = UNDEFINED;
  wcs->obsgeo[1]  = UNDEFINED;
  wcs->obsgeo[2]  = UNDEFINED;
  memset(wcs->radesys, 0, 72);
d553 1
d555 7
a561 1
  memset(wcs->ssyssrc, 0, 72);
a562 1
  memset(wcs->wcsname, 0, 72);
d595 4
a598 5
  const char *pq = "PQ";
  char *c, ctypei[16], ctmp[8], *fp;
  int  axis, axmap[10], cubeface, dealloc, dummy, i, idp, itab, *itmp = 0x0,
       j, jhat, k, latitude, longitude, m, *map, msub, naxis, ndp, ndpmax,
       Nhat, npv, npvmax, nps, npsmax, ntmp, other, spectral, status, stokes;
d601 1
a601 3
  struct tabprm *tab;
  struct disprm *dissrc, *disdst;
  struct dpkey  *dpsrc,  *dpdst;
a607 1
  /* N.B. we do not rely on the wcsprm struct having been set up. */
d620 1
a620 1
  /* Allocate enough temporary storage to hold either axes[] xor map[].*/
d765 1
a765 1
  /* Construct the inverse axis map (i is 0-relative, j is 1-relative):
d781 1
a781 3

  /* Check that the subimage coordinate system is separable.  First check */
  /* non-zero, off-diagonal elements of the linear transformation matrix. */
a793 9
  /* Now check for distortions that depend on other axes.  As the disprm    */
  /* struct may not have been initialized, we must parse the dpkey entries. */
  ndpmax = 0;
  for (m = 0; m < 2; m++) {
    if (m == 0) {
      dissrc = wcssrc->lin.dispre;
    } else {
      dissrc = wcssrc->lin.disseq;
    }
d795 3
a797 27
    ndp = 0;
    if (dissrc != 0x0) {
      for (j = 0; j < naxis; j++) {
        if (map[j] == 0) continue;

        for (jhat = 0; jhat < 10; jhat++) {
          axmap[jhat] = -1;
        }

        Nhat = 0;
        dpsrc = dissrc->dp;
        for (idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
          /* Thorough error checking will be done later by disset(). */
          if (dpsrc->j != j+1) continue;
          if (dpsrc->field[1] != pq[m]) continue;
          if ((fp = strpbrk(dpsrc->field, ".")) == 0x0) continue;
          fp++;

          ndp++;

          if (strncmp(fp, "NAXES", 6) == 0) {
            Nhat = wcsutil_dpkey_int(dpsrc);
          } else if (strncmp(fp, "AXIS.", 5) == 0) {
            sscanf(fp+5, "%d", &jhat);
            axmap[jhat-1] = wcsutil_dpkey_int(dpsrc) - 1;
          }
        }
d799 3
a801 32
        if (Nhat < 0 || (Nhat == 0 && 1 < ndp) || naxis < Nhat) {
          status = wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
            "NAXES was not set (or bad) for %s distortion on axis %d",
            dissrc->dtype[j], j+1);
          goto cleanup;
        }

        for (jhat = 0; jhat < Nhat; jhat++) {
          if (axmap[jhat] < 0) {
            axmap[jhat] = jhat;

            /* Make room for an additional DPja.AXIS.j record. */
            ndp++;
          }

          if (map[axmap[jhat]] == 0) {
            /* Distortion depends on an axis excluded from the subimage. */
            status = wcserr_set(WCS_ERRMSG(WCSERR_NON_SEPARABLE));
            goto cleanup;
          }
        }
      }
    }

    if (ndpmax < ndp) ndpmax = ndp;
  }


  /* Number of PVi_ma records in the subimage. */
  npvmax = 0;
  for (m = 0; m < wcssrc->npv; m++) {
    i = wcssrc->pv[m].i;
d803 1
a803 1
      npvmax++;
a805 2
  npv = wcsnpv(-1);
  wcsnpv(npvmax);
d807 3
a809 4
  /* Number of PSi_ma records in the subimage. */
  npsmax = 0;
  for (m = 0; m < wcssrc->nps; m++) {
    i = wcssrc->ps[m].i;
d811 1
a811 1
      npsmax++;
a813 6
  nps = wcsnps(-1);
  wcsnps(npsmax);

  /* Number of distortion parameters, if any. */
  ndp = disndp(-1);
  disndp(ndpmax);
a814 1
  /* Initialize the destination. */
d817 2
a818 24
  for (m = 0; m < 2; m++) {
    if (m == 0) {
      dissrc = wcssrc->lin.dispre;
      disdst = wcsdst->lin.dispre;
    } else {
      dissrc = wcssrc->lin.disseq;
      disdst = wcsdst->lin.disseq;
    }

    if (dissrc && !disdst) {
      if ((disdst = calloc(1, sizeof(struct disprm))) == 0x0) {
        return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      }

      /* Also inits disdst. */
      disdst->flag = -1;
      lindis(m+1, &(wcsdst->lin), disdst);
    }
  }

  /* Reset WCSNPV, WCSNPS, and DISNDP. */
  wcsnpv(npv);
  wcsnps(nps);
  disndp(ndp);
d838 6
a843 4
    for (j = 0; j < *nsub; j++, dstp++) {
      if (axes[i] > 0 && axes[j] > 0) {
        k = (axes[i]-1)*naxis + (axes[j]-1);
        *dstp = *(srcp+k);
d884 2
a885 2
  for (m = 0; m < wcssrc->npv; m++) {
    i = wcssrc->pv[m].i;
d888 1
a888 1
      wcsdst->pv[npv] = wcssrc->pv[m];
d892 1
a892 1
      wcsdst->pv[npv] = wcssrc->pv[m];
d900 2
a901 2
  for (m = 0; m < wcssrc->nps; m++) {
    i = wcssrc->ps[m].i;
d903 1
a903 1
      wcsdst->ps[nps] = wcssrc->ps[m];
d914 6
a919 8
    for (j = 0; j < *nsub; j++, dstp++) {
      if (axes[i] > 0 && axes[j] > 0) {
        k = (axes[i]-1)*naxis + (axes[j]-1);
        *dstp = *(srcp+k);
      } else if (i == j && wcssrc->altlin & 2) {
        /* A new axis is being created where CDi_ja was present in the input
           header, so override the default value of 0 set by wcsini(). */
        *dstp = 1.0;
d940 1
d951 1
a951 3
  strncpy(wcsdst->dateavg, wcssrc->dateavg, 72);
  strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);

a953 8
  wcsdst->mjdavg = wcssrc->mjdavg;
  wcsdst->mjdobs = wcssrc->mjdobs;

  wcsdst->obsgeo[0] = wcssrc->obsgeo[0];
  wcsdst->obsgeo[1] = wcssrc->obsgeo[1];
  wcsdst->obsgeo[2] = wcssrc->obsgeo[2];

  strncpy(wcsdst->radesys, wcssrc->radesys, 72);
d957 1
a958 3
  strncpy(wcsdst->ssyssrc, wcssrc->ssyssrc, 72);
  wcsdst->velangl = wcssrc->velangl;
  strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);
d960 3
d964 4
a967 96
  /* Distortion parameters. */
  for (m = 0; m < 2; m++) {
    if (m == 0) {
      dissrc = wcssrc->lin.dispre;
      disdst = wcsdst->lin.dispre;
    } else {
      dissrc = wcssrc->lin.disseq;
      disdst = wcsdst->lin.disseq;
    }

    if (dissrc) {
      disdst->naxis = *nsub;

      /* Distortion type and maximum distortion (but not total distortion). */
      for (j = 0; j < *nsub; j++) {
        if (axes[j] > 0) {
          k = axes[j] - 1;
          strncpy(disdst->dtype[j], dissrc->dtype[k], 72);
          disdst->maxdis[j] = dissrc->maxdis[k];
        }
      }

      /* DPja or DQia keyvalues. */
      ndp = 0;
      dpdst = disdst->dp;
      for (j = 0; j < *nsub; j++) {
        if (axes[j] == 0) continue;

        /* Determine the axis mapping. */
        for (jhat = 0; jhat < 10; jhat++) {
          axmap[jhat] = -1;
        }

        dpsrc = dissrc->dp;
        for (idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
          if (dpsrc->j != j+1) continue;
          if (dpsrc->field[1] != pq[m]) continue;
          if ((fp = strpbrk(dpsrc->field, ".")) == 0x0) continue;
          fp++;

          if (strncmp(fp, "NAXES", 6) == 0) {
            Nhat = wcsutil_dpkey_int(dpsrc);
          } else if (strncmp(fp, "AXIS.", 5) == 0) {
            sscanf(fp+5, "%d", &jhat);
            axmap[jhat-1] = wcsutil_dpkey_int(dpsrc) - 1;
          }
        }

        for (jhat = 0; jhat < Nhat; jhat++) {
          if (axmap[jhat] < 0) {
            axmap[jhat] = jhat;
          }
        }

        /* Copy the DPja or DQia keyvalues. */
        dpsrc = dissrc->dp;
        for (idp = 0; idp < dissrc->ndp; idp++, dpsrc++) {
          if (dpsrc->j != axes[j]) continue;
          if (dpsrc->field[1] != pq[m]) continue;
          if ((fp = strpbrk(dpsrc->field, ".")) == 0x0) continue;
          fp++;

          if (strncmp(fp, "AXIS.", 5) == 0) {
            /* Skip it, we will create our own later. */
            continue;
          }

          *dpdst = *dpsrc;
          sprintf(ctmp, "%d", j+1);
          dpdst->field[2] = ctmp[0];
          dpdst->j = j+1;

          ndp++;
          dpdst++;

          if (strncmp(fp, "NAXES", 6) == 0) {
            for (jhat = 0; jhat < Nhat; jhat++) {
              strcpy(dpdst->field, dpsrc->field);
              dpdst->field[2] = ctmp[0];
              fp = strpbrk(dpdst->field, ".") + 1;
              sprintf(fp, "AXIS.%d", jhat+1);
              dpdst->j = j+1;
              dpdst->type = 0;
              dpdst->value.i = map[axmap[jhat]];

              ndp++;
              dpdst++;
            }
          }
        }
      }

      disdst->ndp = ndp;
      disdst->ndpmax = ndpmax;
    }
  }
d996 1
a996 1
  tab = wcsdst->tab;
d1002 1
a1002 1
        if ((status = tabcpy(1, wcssrc->tab + itab, tab))) {
d1007 1
a1007 1
        tab++;
d1702 1
a1702 1
  int    i, j, k, m, n, naxis, ndpmax, status;
a1749 1
      ndpmax = disndp(-1);
a1762 2

      disndp(ndpmax);
@


5.6.1.3
log
@In wcssub(), it is incorrect to copy the value of disprm::ndpmax.  That
must only be set in conjunction with the memory allocated for disprm::dp,
usually by disini().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.6.1.2 2015/06/16 08:20:39 mcalabre Exp mcalabre $
d1166 1
@


5.6.1.4
log
@In wcsset(), re-write wcsprm::ctype for TPU/TPV to prevent wcsset()
attempting to re-translate it if invoked a second time.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.6.1.3 2015/06/16 13:34:46 mcalabre Exp mcalabre $
a2014 5

      /* As the PVi_ma have now been erased, ctype must be reset to prevent
         this translation from re-occurring if wcsset() is called again. */
      strcpy(wcs->ctype[wcs->lng]+5, "TAN");
      strcpy(wcs->ctype[wcs->lat]+5, "TAN");
@


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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.c,v 5.1.1.4 2015/04/15 09:08:37 mcalabre Exp mcalabre $
@


5.2.1.1
log
@WCSLIB 5.2 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 5.0.1.1 2015/04/05 12:28:00 mcalabre Exp mcalabre $
a222 1

d336 1
a336 1
          wcs->pv = (struct pvcard *)0;
d359 1
a359 1
          wcs->ps = (struct pscard *)0;
d1185 1
a1185 1
    /* Free memory allocated by wcsini(). */
d1219 1
a1219 1
      /* Free memory allocated by wcstab(). */
d1230 3
a1232 1
    /* Free memory allocated by wcsset(). */
d1264 2
a1267 5
  if (wcs->err) {
    free(wcs->err);
    wcs->err = 0x0;
  }

d1701 3
a1703 3
  char scode[4], stype[5];
  int i, j, k, m, npv, naxis, nparm, status;
  double lambda, rho, value;
d1706 1
d1750 2
d1757 1
d1761 1
d1764 1
d1768 7
a1774 5
      /* Noting that axmap axis numbers are 1-relative. */
      dis->axmap[wcs->lng][0] = wcs->lng + 1;
      dis->axmap[wcs->lng][1] = wcs->lat + 1;
      dis->axmap[wcs->lat][0] = wcs->lat + 1;
      dis->axmap[wcs->lat][1] = wcs->lng + 1;
d1776 1
a1776 1
      /* What is the maximum parameter index for each celestial axis? */
d1778 3
a1780 6
        i = wcs->pv[k].i - 1;

        if (i == wcs->lng || i == wcs->lat) {
          nparm = wcs->pv[k].m + 1;
          if (dis->nparm[i] < nparm) dis->nparm[i] = nparm;
        }
d1783 5
a1787 7
      /* Determine the correct number of parameters for TPV. */
      for (k = 0; k < 2; k++) {
        if (k == 0) {
          i = wcs->lng;
        } else {
          i = wcs->lat;
        }
d1789 4
a1792 26
        nparm = dis->nparm[i];
        if (nparm <= 4) {
          /* First order. */
          dis->nparm[i] = 4;
        } else if (nparm <= 7) {
          /* Second order. */
          dis->nparm[i] = 7;
        } else if (nparm <= 12) {
          /* Third order. */
          dis->nparm[i] = 12;
        } else if (nparm <= 17) {
          /* Fourth order. */
          dis->nparm[i] = 17;
        } else if (nparm <= 24) {
          /* Fifth order. */
          dis->nparm[i] = 24;
        } else if (nparm <= 31) {
          /* Sixth order. */
          dis->nparm[i] = 31;
        } else if (nparm <= 40) {
          /* Seventh order. */
          dis->nparm[i] = 40;
        } else {
          return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
            "Invalid number of parameters (%d) for %s", nparm, wcsprj->code);
        }
d1795 1
a1795 9
      /* Allocate distortion parameter arrays. */
      disparms(dis);

      /* Copy the distortion parameters. */
      for (k = 0; k < wcs->npv; k++) {
        i = wcs->pv[k].i - 1;
        m = wcs->pv[k].m;
        dis->parms[i][m] = wcs->pv[k].value;
      }
d1797 2
a1798 2
      /* Hide PVi_ma associated with the celestial axes. */
      npv = 0;
d1803 3
a1805 13
        i = wcs->pv[k].i;
        m = wcs->pv[k].m;
        value = wcs->pv[k].value;

        for (j = k; j > npv; j--) {
          wcs->pv[j].i = wcs->pv[j-1].i;
          wcs->pv[j].m = wcs->pv[j-1].m;
          wcs->pv[j].value = wcs->pv[j-1].value;
        }

        wcs->pv[npv].i = i;
        wcs->pv[npv].m = m;
        wcs->pv[npv].value = value;
d1807 1
a1807 1
        npv++;
d1810 1
a1810 1
      wcs->npv = npv;
@


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


5.1.1.2
log
@Polish.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.1.1.1 2015/04/07 11:01:10 mcalabre Exp mcalabre $
d223 1
d337 1
a337 1
          wcs->pv = 0x0;
d360 1
a360 1
          wcs->ps = 0x0;
@


5.1.1.3
log
@In wcsset(), use the new API for disprm when translating TPV.  In wcsfree(),
don't try to free err if flag == -1.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.1.1.2 2015/04/10 15:47:22 mcalabre Exp mcalabre $
a1229 2
    if (wcs->err) free(wcs->err);

d1262 1
a1262 1
  wcs->err  = 0x0;
d1264 4
a1267 1
  wcs->flag = 0;
d1702 3
a1704 3
  char   dpq[8], scode[4], stype[5];
  int i, j, k, m, n, naxis, status;
  double lambda, rho;
a1706 1
  struct dpkey  *keyp;
a1749 2
      disndp(6+wcs->npv);

a1754 1
        strcpy(dpq, "DP");
a1757 1
        strcpy(dpq, "DQ");
a1759 1
      /* Yes, the distortion type is "TPV" even for TPU. */
d1763 9
a1771 2
      /* Keep the keywords in axis-order to aid debugging. */
      keyp = dis->dp;
d1773 5
a1777 4
      sprintf(dpq+2, "%d", wcs->lng+1);
      dpfill(keyp++, dpq, "NAXES",  0, 0, 2, 0.0);
      dpfill(keyp++, dpq, "AXIS.1", 0, 0, 1, 0.0);
      dpfill(keyp++, dpq, "AXIS.2", 0, 0, 2, 0.0);
d1779 34
a1812 5
      /* Copy distortion parameters for the longitude axis. */
      for (k = 0; k < wcs->npv; k++) {
        if (wcs->pv[k].i != wcs->lng+1) continue;
        sprintf(keyp->field, "%s.TPV.%d", dpq, wcs->pv[k].m);
        dpfill(keyp++, 0x0, 0x0, 0, 1, 0, wcs->pv[k].value);
d1815 2
a1816 5
      /* Now the latitude axis. */
      sprintf(dpq+2, "%d", wcs->lat+1);
      dpfill(keyp++, dpq, "NAXES",  0, 0, 2, 0.0);
      dpfill(keyp++, dpq, "AXIS.1", 0, 0, 2, 0.0);
      dpfill(keyp++, dpq, "AXIS.2", 0, 0, 1, 0.0);
d1818 1
d1820 3
a1822 3
        if (wcs->pv[k].i != wcs->lat+1) continue;
        sprintf(keyp->field, "%s.TPV.%d", dpq, wcs->pv[k].m);
        dpfill(keyp++, 0x0, 0x0, 0, 1, 0, wcs->pv[k].value);
d1825 2
a1826 4
      dis->ndp = keyp - dis->dp;

      /* Erase PVi_ma associated with the celestial axes. */
      n = 0;
d1831 13
a1843 3
        wcs->pv[n].i = wcs->pv[k].i;
        wcs->pv[n].m = wcs->pv[k].m;
        wcs->pv[n].value = wcs->pv[k].value;
d1845 1
a1845 1
        n++;
d1848 1
a1848 1
      wcs->npv = n;
@


5.1.1.4
log
@Minor tweaks to comments in wcsfree().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 5.1.1.3 2015/04/13 08:35:43 mcalabre Exp mcalabre $
d1185 1
a1185 1
    /* Optionally allocated by wcsini() for given parameters. */
d1219 1
a1219 1
      /* Allocated unconditionally by wcstab(). */
d1232 1
a1232 1
    /* Allocated unconditionally by wcsset(). */
@


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: wcs.c,v 4.25.1.6 2015/04/05 06:00:29 mcalabre Exp mcalabre $
@


5.0.1.1
log
@WCSLIB 5.0 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 4.24.1.2 2014/12/09 04:29:22 mcalabre Exp mcalabre $
d40 1
d61 1
a61 1
  "Inconsistent or unrecognized coordinate axis types",
d63 2
a64 2
  "Invalid coordinate transformation parameters",
  "Ill-conditioned coordinate transformation parameters",
d72 47
a154 1
    if (wcs->cel.prj.err) free(wcs->cel.prj.err);
a159 1
  wcs->cel.prj.err = 0x0;
d165 1
a167 1
      wcs->tab = 0x0;
d230 1
a230 1
        if (!(wcs->crpix = calloc(naxis, sizeof(double)))) {
d246 1
a246 1
        if (!(wcs->pc = calloc(naxis*naxis, sizeof(double)))) {
d263 1
a263 1
        if (!(wcs->cdelt = calloc(naxis, sizeof(double)))) {
d280 1
a280 1
        if (!(wcs->crval = calloc(naxis, sizeof(double)))) {
d297 1
a297 1
        if (!(wcs->cunit = calloc(naxis, sizeof(char [72])))) {
d314 1
a314 1
        if (!(wcs->ctype = calloc(naxis, sizeof(char [72])))) {
d332 1
a332 1
          if (!(wcs->pv = calloc(NPVMAX, sizeof(struct pvcard)))) {
d355 1
a355 1
          if (!(wcs->ps = calloc(NPSMAX, sizeof(struct pscard)))) {
d377 1
a377 1
        if (!(wcs->cd = calloc(naxis*naxis, sizeof(double)))) {
d394 1
a394 1
        if (!(wcs->crota = calloc(naxis, sizeof(double)))) {
d411 1
a411 1
        if (!(wcs->colax = calloc(naxis, sizeof(int)))) {
d428 1
a428 1
        if (!(wcs->cname = calloc(naxis, sizeof(char [72])))) {
d445 1
a445 1
        if (!(wcs->crder = calloc(naxis, sizeof(double)))) {
d462 1
a462 1
        if (!(wcs->csyer = calloc(naxis, sizeof(double)))) {
a482 1
  wcs->lin.m_flag = 0;
d484 1
a484 1
    return wcserr_set(WCS_ERRMSG(status));
d623 1
a623 1
  if (!(itmp = calloc(ntmp, sizeof(int)))) {
d629 1
a629 1
    if (!(axes = calloc(naxis, sizeof(int)))) {
d987 1
a987 1
    if (!(wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm)))) {
d1004 1
a1004 1
          wcserr_set(WCS_ERRMSG(status));
d1021 5
a1025 1
  if (status && wcsdst->m_tab) free(wcsdst->m_tab);
d1297 1
a1297 1
    wcsprintf("  %- 11.5g", wcs->crpix[i]);
d1307 1
a1307 1
      wcsprintf("  %- 11.5g", wcs->pc[k++]);
d1316 1
a1316 1
    wcsprintf("  %- 11.5g", wcs->cdelt[i]);
d1324 1
a1324 1
    wcsprintf("  %- 11.5g", wcs->crval[i]);
d1354 1
a1354 1
    wcsprintf("             %3d%4d  %- 11.5g\n", (wcs->pv[i]).i,
d1372 1
a1372 1
        wcsprintf("  %- 11.5g", wcs->cd[k++]);
d1382 1
a1382 1
      wcsprintf("  %- 11.5g", wcs->crota[i]);
d1429 1
a1429 1
        wcsprintf("  %- 11.5g", wcs->crder[i]);
d1442 1
a1442 1
        wcsprintf("  %- 11.5g", wcs->csyer[i]);
d1495 1
a1495 1
      wcsprintf("%- 11.5g  ", wcs->obsgeo[i]);
d1664 3
a1666 4
  if (!wcserr_prt(wcs->err, prefix)) {
    wcserr_prt(wcs->lin.err, prefix);
    wcserr_prt(wcs->cel.err, prefix);
    wcserr_prt(wcs->cel.prj.err, prefix);
d1704 2
a1705 2
  int i, j, k, m, naxis, status;
  double lambda, rho;
d1707 2
d1728 2
d1741 112
a1914 4

    } else {
      strncpy(wcsprj->code, wcs->ctype[wcs->lng]+5, 3);
      wcsprj->code[3] = '\0';
d1920 1
a1920 1
      return wcserr_set(WCS_ERRMSG(status+3));
d1981 1
a1981 1
      return wcserr_set(WCS_ERRMSG(status+3));
d1989 1
a1989 1
      return wcserr_set(WCS_ERRMSG(status+3));
a1994 1
  naxis = wcs->naxis;
d2032 1
a2032 1
    return wcserr_set(WCS_ERRMSG(status));
d2095 2
a2096 2
  const int  nalias = 2;
  const char aliases [2][4] = {"NCP", "GLS"};
d2119 1
a2119 2
  wcs->types = calloc(naxis, sizeof(int));
  if (wcs->types == NULL) {
d2467 1
a2467 1
    return wcserr_set(WCS_ERRMSG(status));
d2471 1
a2471 1
  if (!(istatp = calloc(ncoord, sizeof(int)))) {
d2562 5
a2566 5
        if (istat == CELERR_BAD_PIX) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
        } else {
          status = wcserr_set(WCS_ERRMSG(istat+3));
          goto cleanup;
d2596 5
a2600 5
        if (istat == SPCERR_BAD_X) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
        } else if (istat) {
          status = wcserr_set(WCS_ERRMSG(istat+3));
          goto cleanup;
d2606 4
a2609 3
        if (istat == LOGERR_BAD_X) {
          if (*err == 0x0) {
            wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
a2610 3
        } else if (istat == LOGERR_BAD_LOG_REF_VAL) {
          wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM), log_errmsg[istat]);
          goto cleanup;
d2631 2
a2632 2
    if (istat == TABERR_BAD_X) {
      status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
d2634 10
a2643 10
      bits = 0;
      for (m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
      }
      wcsutil_setBit(ncoord, istatp, bits, stat);

    } else if (istat) {
      if (istat == TABERR_BAD_PARAMS) istat = WCSERR_BAD_PARAM;
      status = wcserr_set(WCS_ERRMSG(istat));
      goto cleanup;
d2700 1
a2700 1
  if (!(istatp = calloc(ncoord, sizeof(int)))) {
d2742 5
a2746 5
        if (istat == CELERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
        } else {
          status = wcserr_set(WCS_ERRMSG(istat+3));
          goto cleanup;
d2811 5
a2815 5
        if (istat == SPCERR_BAD_SPEC) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
        } else if (istat) {
          status = wcserr_set(WCS_ERRMSG(istat+3));
          goto cleanup;
d2821 5
a2825 6
        if (istat == LOGERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
        } else if (istat == LOGERR_BAD_LOG_REF_VAL) {
          status = wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
                     log_errmsg[istat]);
          goto cleanup;
d2846 2
a2847 2
    if (istat == TABERR_BAD_WORLD) {
      status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
d2849 10
a2858 10
      bits = 0;
      for (m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
      }
      wcsutil_setBit(ncoord, istatp, bits, stat);

    } else if (istat) {
      if (istat == TABERR_BAD_PARAMS) istat = WCSERR_BAD_PARAM;
      status = wcserr_set(WCS_ERRMSG(istat));
      goto cleanup;
d2872 1
a2872 1
    status = wcserr_set(WCS_ERRMSG(istat));
d3572 4
a3575 3
  if (spctrne(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j], wcs->restfrq,
              wcs->restwav, ctype, &crval, &cdelt, &(wcs->spc.err))) {
    return wcserr_set(WCS_ERRMSG(WCSERR_BAD_COORD_TRANS));
d3591 19
@


4.25.1.1
log
@WCSLIB 4.25 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.c,v 4.25.1.1 2014/12/14 14:32:45 mcalabre Exp mcalabre $
@


4.25.1.3
log
@Added function wcslib_version() to return the WCSLIB version number.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.25.1.2 2015/01/06 01:01:06 mcalabre Exp mcalabre $
a3434 19
}

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

#define STRINGIZE(s) STRINGIFY(s)
#define STRINGIFY(s) #s

const char *wcslib_version(
  int  vers[3])

{
  static const char *wcsver = STRINGIZE(WCSLIB_VERSION);

  if (vers != 0x0) {
    vers[2] = 0;
    sscanf(wcsver, "%d.%d.%d", vers, vers+1, vers+2);
  }

  return wcsver;
@


4.25.1.4
log
@Created wcs_linerr[], wcs_logerr[], wcs_spcerr[], wcs_celerr[], and
wcs_taberr[] to map status returns from the lower-level routines.  Tidied
up error handling in wcsp2s() and wcss2p().  wcsperr() now uses linperr()
and celperr().  wcsset() translates TPU and TPV into a disprm struct.
Tweaked output formatting in wcsprt().  Housecleaning in wcsini() and
wcssub().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.25.1.3 2015/03/05 08:20:35 mcalabre Exp mcalabre $
a39 1
#include "dis.h"
d60 1
a60 1
  "Inconsistent or unrecognized coordinate axis type",
d62 2
a63 2
  "Unrecognized coordinate transformation parameter",
  "Ill-conditioned coordinate transformation parameter",
a70 47
/* Map error returns for lower-level routines. */
const int wcs_linerr[] = {
  WCSERR_SUCCESS,		/*  0: LINERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: LINERR_NULL_POINTER    */
  WCSERR_MEMORY,		/*  2: LINERR_MEMORY          */
  WCSERR_SINGULAR_MTX,		/*  3: LINERR_SINGULAR_MTX    */
  WCSERR_BAD_PARAM,		/*  4: LINERR_DISTORT_INIT    */
  WCSERR_BAD_PIX,		/*  5: LINERR_DISTORT         */
  WCSERR_BAD_WORLD		/*  6: LINERR_DEDISTORT       */
};

const int wcs_logerr[] = {
  WCSERR_SUCCESS,		/*  0: LOGERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: LOGERR_NULL_POINTER    */
  WCSERR_BAD_PARAM,		/*  2: LOGERR_BAD_LOG_REF_VAL */
  WCSERR_BAD_PIX,		/*  3: LOGERR_BAD_X           */
  WCSERR_BAD_WORLD		/*  4: LOGERR_BAD_WORLD       */
};

const int wcs_spcerr[] = {
				/* -1: SPCERR_NO_CHANGE       */
  WCSERR_SUCCESS,		/*  0: SPCERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: SPCERR_NULL_POINTER    */
  WCSERR_BAD_PARAM,		/*  2: SPCERR_BAD_SPEC_PARAMS */
  WCSERR_BAD_PIX,		/*  3: SPCERR_BAD_X           */
  WCSERR_BAD_WORLD		/*  4: SPCERR_BAD_SPEC        */
};

const int wcs_celerr[] = {
  WCSERR_SUCCESS,		/*  0: CELERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: CELERR_NULL_POINTER    */
  WCSERR_BAD_PARAM,		/*  2: CELERR_BAD_PARAM       */
  WCSERR_BAD_COORD_TRANS,	/*  3: CELERR_BAD_COORD_TRANS */
  WCSERR_ILL_COORD_TRANS,	/*  4: CELERR_ILL_COORD_TRANS */
  WCSERR_BAD_PIX,		/*  5: CELERR_BAD_PIX         */
  WCSERR_BAD_WORLD		/*  6: CELERR_BAD_WORLD       */
};

const int wcs_taberr[] = {
  WCSERR_SUCCESS,		/*  0: TABERR_SUCCESS         */
  WCSERR_NULL_POINTER,		/*  1: TABERR_NULL_POINTER    */
  WCSERR_MEMORY,		/*  2: TABERR_MEMORY          */
  WCSERR_BAD_PARAM,		/*  3: TABERR_BAD_PARAMS      */
  WCSERR_BAD_PIX,		/*  4: TABERR_BAD_X           */
  WCSERR_BAD_WORLD		/*  5: TABERR_BAD_WORLD       */
};

a118 1
      wcs->tab   = 0x0;
d121 1
d184 1
a184 1
        if ((wcs->crpix = calloc(naxis, sizeof(double))) == 0x0) {
d200 1
a200 1
        if ((wcs->pc = calloc(naxis*naxis, sizeof(double))) == 0x0) {
d217 1
a217 1
        if ((wcs->cdelt = calloc(naxis, sizeof(double))) == 0x0) {
d234 1
a234 1
        if ((wcs->crval = calloc(naxis, sizeof(double))) == 0x0) {
d251 1
a251 1
        if ((wcs->cunit = calloc(naxis, sizeof(char [72]))) == 0x0) {
d268 1
a268 1
        if ((wcs->ctype = calloc(naxis, sizeof(char [72]))) == 0x0) {
d286 1
a286 1
          if ((wcs->pv = calloc(NPVMAX, sizeof(struct pvcard))) == 0x0) {
d309 1
a309 1
          if ((wcs->ps = calloc(NPSMAX, sizeof(struct pscard))) == 0x0) {
d331 1
a331 1
        if ((wcs->cd = calloc(naxis*naxis, sizeof(double))) == 0x0) {
d348 1
a348 1
        if ((wcs->crota = calloc(naxis, sizeof(double))) == 0x0) {
d365 1
a365 1
        if ((wcs->colax = calloc(naxis, sizeof(int))) == 0x0) {
d382 1
a382 1
        if ((wcs->cname = calloc(naxis, sizeof(char [72]))) == 0x0) {
d399 1
a399 1
        if ((wcs->crder = calloc(naxis, sizeof(double))) == 0x0) {
d416 1
a416 1
        if ((wcs->csyer = calloc(naxis, sizeof(double))) == 0x0) {
d437 1
d439 1
a439 1
    return wcserr_set(WCS_ERRMSG(wcs_linerr[status]));
d578 1
a578 1
  if ((itmp = calloc(ntmp, sizeof(int))) == 0x0) {
d584 1
a584 1
    if ((axes = calloc(naxis, sizeof(int))) == 0x0) {
d942 1
a942 1
    if ((wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm))) == 0x0) {
d959 1
a959 1
          wcserr_set(WCS_ERRMSG(wcs_taberr[status]));
d976 1
a976 5
  if (status && wcsdst->m_tab) {
    free(wcsdst->m_tab);
    wcsdst->tab   = 0x0;
    wcsdst->m_tab = 0x0;
  }
d1248 1
a1248 1
    wcsprintf("  %#- 11.5g", wcs->crpix[i]);
d1258 1
a1258 1
      wcsprintf("  %#- 11.5g", wcs->pc[k++]);
d1267 1
a1267 1
    wcsprintf("  %#- 11.5g", wcs->cdelt[i]);
d1275 1
a1275 1
    wcsprintf("  %#- 11.5g", wcs->crval[i]);
d1305 1
a1305 1
    wcsprintf("             %3d%4d  %#- 11.5g\n", (wcs->pv[i]).i,
d1323 1
a1323 1
        wcsprintf("  %#- 11.5g", wcs->cd[k++]);
d1333 1
a1333 1
      wcsprintf("  %#- 11.5g", wcs->crota[i]);
d1380 1
a1380 1
        wcsprintf("  %#- 11.5g", wcs->crder[i]);
d1393 1
a1393 1
        wcsprintf("  %#- 11.5g", wcs->csyer[i]);
d1446 1
a1446 1
      wcsprintf("  %#- 11.5g", wcs->obsgeo[i]);
d1616 3
a1618 2
    linperr(&(wcs->lin), prefix);
    celperr(&(wcs->cel), prefix);
d1656 2
a1657 2
  int i, j, k, m, npv, naxis, nparm, status;
  double lambda, rho, value;
a1658 2
  struct disprm *dis;
  struct linprm *wcslin = &(wcs->lin);
a1677 2
  naxis = wcs->naxis;

a1688 112
    /* Do alias translation for TPU/TPV before dealing with PVi_ma. */
    strncpy(wcsprj->code, wcs->ctype[wcs->lng]+5, 3);
    wcsprj->code[3] = '\0';
    if (strncmp(wcsprj->code, "TPU", 3) == 0 ||
        strncmp(wcsprj->code, "TPV", 3) == 0) {
      /* Translate the PV parameters. */
      if ((dis = calloc(naxis, sizeof(struct disprm))) == 0x0) {
        return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
      }

      /* Attach it to linprm.  Also inits it. */
      dis->flag = -1;
      if (strncmp(wcsprj->code, "TPU", 3) == 0) {
        /* Prior distortion. */
        lindis(1, wcslin, dis);
      } else {
        /* Sequent distortion. */
        lindis(2, wcslin, dis);
      }

      strcpy(dis->dtype[wcs->lng], "TPV");
      strcpy(dis->dtype[wcs->lat], "TPV");

      /* Noting that axmap axis numbers are 1-relative. */
      dis->axmap[wcs->lng][0] = wcs->lng + 1;
      dis->axmap[wcs->lng][1] = wcs->lat + 1;
      dis->axmap[wcs->lat][0] = wcs->lat + 1;
      dis->axmap[wcs->lat][1] = wcs->lng + 1;

      /* What is the maximum parameter index for each celestial axis? */
      for (k = 0; k < wcs->npv; k++) {
        i = wcs->pv[k].i - 1;

        if (i == wcs->lng || i == wcs->lat) {
          nparm = wcs->pv[k].m + 1;
          if (dis->nparm[i] < nparm) dis->nparm[i] = nparm;
        }
      }

      /* Determine the correct number of parameters for TPV. */
      for (k = 0; k < 2; k++) {
        if (k == 0) {
          i = wcs->lng;
        } else {
          i = wcs->lat;
        }

        nparm = dis->nparm[i];
        if (nparm <= 4) {
          /* First order. */
          dis->nparm[i] = 4;
        } else if (nparm <= 7) {
          /* Second order. */
          dis->nparm[i] = 7;
        } else if (nparm <= 12) {
          /* Third order. */
          dis->nparm[i] = 12;
        } else if (nparm <= 17) {
          /* Fourth order. */
          dis->nparm[i] = 17;
        } else if (nparm <= 24) {
          /* Fifth order. */
          dis->nparm[i] = 24;
        } else if (nparm <= 31) {
          /* Sixth order. */
          dis->nparm[i] = 31;
        } else if (nparm <= 40) {
          /* Seventh order. */
          dis->nparm[i] = 40;
        } else {
          return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
            "Invalid number of parameters (%d) for %s", nparm, wcsprj->code);
        }
      }

      /* Allocate distortion parameter arrays. */
      disalloc(dis);

      /* Copy the distortion parameters. */
      for (k = 0; k < wcs->npv; k++) {
        i = wcs->pv[k].i - 1;
        m = wcs->pv[k].m;
        dis->parms[i][m] = wcs->pv[k].value;
      }

      /* Hide PVi_ma associated with the celestial axes. */
      npv = 0;
      for (k = 0; k < wcs->npv; k++) {
        i = wcs->pv[k].i - 1;
        if (i == wcs->lng || i == wcs->lat) continue;

        i = wcs->pv[k].i;
        m = wcs->pv[k].m;
        value = wcs->pv[k].value;

        for (j = k; j > npv; j--) {
          wcs->pv[j].i = wcs->pv[j-1].i;
          wcs->pv[j].m = wcs->pv[j-1].m;
          wcs->pv[j].value = wcs->pv[j-1].value;
        }

        wcs->pv[npv].i = i;
        wcs->pv[npv].m = m;
        wcs->pv[npv].value = value;

        npv++;
      }

      wcs->npv = npv;
      strcpy(wcsprj->code, "TAN");
    }

d1751 4
d1760 1
a1760 1
      return wcserr_set(WCS_ERRMSG(wcs_celerr[status]));
d1821 1
a1821 1
      return wcserr_set(WCS_ERRMSG(wcs_spcerr[status]));
d1829 1
a1829 1
      return wcserr_set(WCS_ERRMSG(wcs_taberr[status]));
d1835 1
d1873 1
a1873 1
    return wcserr_set(WCS_ERRMSG(wcs_linerr[status]));
d1936 2
a1937 2
  const int  nalias = 4;
  const char aliases [4][4] = {"NCP", "GLS", "TPU", "TPV"};
d1960 2
a1961 1
  if ((wcs->types = calloc(naxis, sizeof(int))) == 0x0) {
d2309 1
a2309 1
    return wcserr_set(WCS_ERRMSG(wcs_linerr[status]));
d2313 1
a2313 1
  if ((istatp = calloc(ncoord, sizeof(int))) == 0x0) {
d2404 5
a2408 5
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
          if (status != WCSERR_BAD_PIX) {
            goto cleanup;
          }
d2438 5
a2442 5
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_spcerr[istat]));
          if (status != WCSERR_BAD_PIX) {
            goto cleanup;
          }
d2448 3
a2450 4
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_logerr[istat]));
          if (status != WCSERR_BAD_PIX) {
            goto cleanup;
d2452 3
d2475 2
a2476 2
    if (istat) {
      status = wcserr_set(WCS_ERRMSG(wcs_taberr[istat]));
d2478 10
a2487 10
      if (status != WCSERR_BAD_PIX) {
        goto cleanup;

      } else {
        bits = 0;
        for (m = 0; m < wcs->tab[itab].M; m++) {
          bits |= 1 << wcs->tab[itab].map[m];
        }
        wcsutil_setBit(ncoord, istatp, bits, stat);
      }
d2544 1
a2544 1
  if ((istatp = calloc(ncoord, sizeof(int))) == 0x0) {
d2586 5
a2590 5
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_celerr[istat]));
          if (status != WCSERR_BAD_WORLD) {
            goto cleanup;
          }
d2655 5
a2659 5
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_spcerr[istat]));
          if (status != WCSERR_BAD_WORLD) {
            goto cleanup;
          }
d2665 6
a2670 5
        if (istat) {
          status = wcserr_set(WCS_ERRMSG(wcs_logerr[istat]));
          if (status != WCSERR_BAD_WORLD) {
            goto cleanup;
          }
d2691 2
a2692 2
    if (istat) {
      status = wcserr_set(WCS_ERRMSG(wcs_taberr[istat]));
d2694 10
a2703 10
      if (status == WCSERR_BAD_WORLD) {
        bits = 0;
        for (m = 0; m < wcs->tab[itab].M; m++) {
          bits |= 1 << wcs->tab[itab].map[m];
        }
        wcsutil_setBit(ncoord, istatp, bits, stat);

      } else {
        goto cleanup;
      }
d2717 1
a2717 1
    status = wcserr_set(WCS_ERRMSG(wcs_linerr[istat]));
d3417 3
a3419 4
  if ((status = spctrne(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                        wcs->restfrq, wcs->restwav, ctype, &crval, &cdelt,
                        &(wcs->spc.err)))) {
    return wcserr_set(WCS_ERRMSG(wcs_spcerr[status]));
@


4.25.1.5
log
@Care must be exercised in attempting to report errors that may occur within
wcsini(), because the dependent structs usually won't have been initialised.
This applies specifically to celprm::prj, linprm::dispre, and linprm::disseq.
Thus, wcsini() initialises wcs->lin.err, wcs->cel.err, and wcs->spc.err at
the outset, and wcsperr() mustn't attempt to report errors from its dependent
structs unless wcs->err itself has been set.  The same also applies to
linperr() and celperr().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.25.1.4 2015/04/03 02:17:33 mcalabre Exp mcalabre $
d155 1
d161 1
d1666 1
a1666 1
  if (wcs->err && wcserr_prt(wcs->err, prefix) == 0) {
@


4.25.1.6
log
@In wcsset(), only need to allocate one disprm struct for TPU/TPV.
disalloc() renamed to disparms().
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.25.1.5 2015/04/03 04:02:46 mcalabre Exp mcalabre $
d1747 1
a1747 1
      if ((dis = calloc(1, sizeof(struct disprm))) == 0x0) {
d1817 1
a1817 1
      disparms(dis);
@


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: wcs.c,v 4.23.1.2 2014/05/22 11:05:11 mcalabre Exp mcalabre $
d1877 34
a2022 1
        if (wcs->lng < 0) wcs->lng = i;
d2024 4
a2032 1
        if (wcs->lat < 0) wcs->lat = i;
d2034 4
@


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


4.24.1.2
log
@In wcsset(), if necessary, efaults for radesys and equinox for equatorial
or ecliptic coordinates.  Also ensure that wcsprm::lngtyp and lattyp are
set for linear celestial coordinates.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.24.1.1 2014/09/18 15:28:09 mcalabre Exp mcalabre $
a1876 34
  /* Set defaults for radesys and equinox for equatorial or ecliptic. */
  if (strcmp(wcs->lngtyp, "RA")   == 0 ||
      strcmp(wcs->lngtyp, "ELON") == 0 ||
      strcmp(wcs->lngtyp, "HLON") == 0) {
    if (wcs->radesys[0] == '\0') {
      if (undefined(wcs->equinox)) {
        strcpy(wcs->radesys, "ICRS");
      } else if (wcs->equinox < 1984.0) {
        strcpy(wcs->radesys, "FK4");
      } else {
        strcpy(wcs->radesys, "FK5");
      }

    } else if (strcmp(wcs->radesys, "ICRS")  == 0 ||
               strcmp(wcs->radesys, "GAPPT") == 0) {
      /* Equinox is not applicable for these coordinate systems. */
      wcs->equinox = UNDEFINED;

    } else if (undefined(wcs->equinox)) {
      if (strcmp(wcs->radesys, "FK5") == 0) {
        wcs->equinox = 2000.0;
      } else if (strcmp(wcs->radesys, "FK4") == 0 ||
                 strcmp(wcs->radesys, "FK4-NO-E") == 0) {
        wcs->equinox = 1950.0;
      }
    }

  } else {
    /* No celestial axes, ensure that radesys and equinox are unset. */
    memset(wcs->radesys, 0, 72);
    wcs->equinox = UNDEFINED;
  }


d1989 1
a1990 4
        if (wcs->lng < 0) {
          wcs->lng = i;
          strcpy(wcs->lngtyp, ctypei);
        }
d1996 1
a1997 4
        if (wcs->lat < 0) {
          wcs->lat = i;
          strcpy(wcs->lattyp, ctypei);
        }
@


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: wcs.c,v 4.22.1.3 2014/05/10 14:29:04 mcalabre Exp mcalabre $
d985 1
d1019 1
a1019 1
    if (!wcsutil_Eq(naxis, wcs1->crpix, wcs2->crpix)) {
d1024 3
a1026 3
  if (!wcsutil_Eq(naxis2, wcs1->pc, wcs2->pc) ||
      !wcsutil_Eq(naxis, wcs1->cdelt, wcs2->cdelt) ||
      !wcsutil_Eq(naxis, wcs1->crval, wcs2->crval) ||
d1029 4
a1032 4
      wcs1->lonpole != wcs2->lonpole ||
      wcs1->latpole != wcs2->latpole ||
      wcs1->restfrq != wcs2->restfrq ||
      wcs1->restwav != wcs2->restwav ||
d1043 1
a1043 1
        if (wcs1->pv[i].value != wcs2->pv[j].value) {
d1073 2
a1074 2
    if (!wcsutil_Eq(naxis2, wcs1->cd, wcs2->cd) ||
        !wcsutil_Eq(naxis, wcs1->crota, wcs2->crota) ||
d1086 2
a1087 2
        !wcsutil_Eq(naxis, wcs1->crder, wcs2->crder) ||
        !wcsutil_Eq(naxis, wcs1->csyer, wcs2->csyer) ||
d1090 4
a1093 4
        wcs1->equinox != wcs2->equinox ||
        wcs1->mjdavg != wcs2->mjdavg ||
        wcs1->mjdobs != wcs2->mjdobs ||
        !wcsutil_Eq(3, wcs1->obsgeo, wcs2->obsgeo) ||
d1097 2
a1098 2
        wcs1->velosys != wcs2->velosys ||
        wcs1->zsource != wcs2->zsource ||
d1100 1
a1100 1
        wcs1->velangl != wcs2->velangl ||
d1112 1
a1112 1
    if ((status = tabcmp(0, &wcs1->tab[i], &wcs2->tab[i], &tab_equal))) {
@


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


4.23.1.2
log
@Changed API to wcscompare() to allow a tolerance to be specified for
floating-point comparisons.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.23.1.1 2014/05/13 05:53:49 mcalabre Exp mcalabre $
a984 1
  double tol,
d1018 1
a1018 1
    if (!wcsutil_Eq(naxis, tol, wcs1->crpix, wcs2->crpix)) {
d1023 3
a1025 3
  if (!wcsutil_Eq(naxis2, tol, wcs1->pc, wcs2->pc) ||
      !wcsutil_Eq(naxis, tol, wcs1->cdelt, wcs2->cdelt) ||
      !wcsutil_Eq(naxis, tol, wcs1->crval, wcs2->crval) ||
d1028 4
a1031 4
      !wcsutil_Eq(1, tol, &wcs1->lonpole, &wcs2->lonpole) ||
      !wcsutil_Eq(1, tol, &wcs1->latpole, &wcs2->latpole) ||
      !wcsutil_Eq(1, tol, &wcs1->restfrq, &wcs2->restfrq) ||
      !wcsutil_Eq(1, tol, &wcs1->restwav, &wcs2->restwav) ||
d1042 1
a1042 1
        if (!wcsutil_Eq(1, tol, &wcs1->pv[i].value, &wcs2->pv[j].value)) {
d1072 2
a1073 2
    if (!wcsutil_Eq(naxis2, tol, wcs1->cd, wcs2->cd) ||
        !wcsutil_Eq(naxis, tol, wcs1->crota, wcs2->crota) ||
d1085 2
a1086 2
        !wcsutil_Eq(naxis, tol, wcs1->crder, wcs2->crder) ||
        !wcsutil_Eq(naxis, tol, wcs1->csyer, wcs2->csyer) ||
d1089 4
a1092 4
        !wcsutil_Eq(1, tol, &wcs1->equinox, &wcs2->equinox) ||
        !wcsutil_Eq(1, tol, &wcs1->mjdavg, &wcs2->mjdavg) ||
        !wcsutil_Eq(1, tol, &wcs1->mjdobs, &wcs2->mjdobs) ||
        !wcsutil_Eq(3, tol, wcs1->obsgeo, wcs2->obsgeo) ||
d1096 2
a1097 2
        !wcsutil_Eq(1, tol, &wcs1->velosys, &wcs2->velosys) ||
        !wcsutil_Eq(1, tol, &wcs1->zsource, &wcs2->zsource) ||
d1099 1
a1099 1
        !wcsutil_Eq(1, tol, &wcs1->velangl, &wcs2->velangl) ||
d1111 1
a1111 1
    if ((status = tabcmp(0, tol, &wcs1->tab[i], &wcs2->tab[i], &tab_equal))) {
@


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: wcs.c,v 4.21.1.1 2014/03/24 05:15:28 mcalabre Exp mcalabre $
d518 1
d552 3
a554 2
  int  axis, cubeface, dealloc, dummy, i, itab, j, k, latitude, longitude, m,
       *map = 0x0, msub, naxis, npv, nps, other, spectral, status, stokes;
a568 4
  if (!(map = calloc(naxis, sizeof(int)))) {
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
  }

d576 6
d585 1
a585 1
      free(map);
d685 1
a685 1
          if (map[k] == i+1) {
d689 1
a689 1
        if (k == msub) map[msub++] = i+1;
d695 1
a695 1
        if (map[k] == axis) {
d699 1
a699 1
      if (k == msub) map[msub++] = axis;
d703 1
a703 1
      map[msub++] = 0;
d717 1
a717 1
    axes[i] = map[i];
d726 1
d738 4
a741 5
  if (*nsub < naxis) {
    srcp = wcssrc->pc;
    for (i = 0; i < naxis; i++) {
      for (j = 0; j < naxis; j++) {
        if (*(srcp++) == 0.0 || j == i) continue;
d743 3
a745 4
        if ((map[i] == 0) != (map[j] == 0)) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_NON_SEPARABLE));
          goto cleanup;
        }
d971 1
a971 1
  if (map) free(map);
d979 142
@


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


4.22.1.2
log
@In wcssub(), fixed a bug uncovered by valgrind arising from allocation of
insufficient memory for temporaries when a new axis is added.  Reported
by Michael Droettboom.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.22.1.1 2014/04/12 15:06:32 mcalabre Exp mcalabre $
d551 2
a552 3
  int  axis, cubeface, dealloc, dummy, i, itab, *itmp = 0x0, j, k, latitude,
       longitude, m, *map, msub, naxis, npv, nps, ntmp, other, spectral,
       status, stokes;
d567 4
a577 6
  /* Allocate enough temporary storage to hold either axes[] or map[].*/
  ntmp = (*nsub <= naxis) ? naxis : *nsub;
  if (!(itmp = calloc(ntmp, sizeof(int)))) {
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
  }

d581 1
a581 1
      free(itmp);
d681 1
a681 1
          if (itmp[k] == i+1) {
d685 1
a685 1
        if (k == msub) itmp[msub++] = i+1;
d691 1
a691 1
        if (itmp[k] == axis) {
d695 1
a695 1
      if (k == msub) itmp[msub++] = axis;
d699 1
a699 1
      itmp[msub++] = 0;
d713 1
a713 1
    axes[i] = itmp[i];
a721 1
  map = itmp;
d733 5
a737 4
  srcp = wcssrc->pc;
  for (i = 0; i < naxis; i++) {
    for (j = 0; j < naxis; j++) {
      if (*(srcp++) == 0.0 || j == i) continue;
d739 4
a742 3
      if ((map[i] == 0) != (map[j] == 0)) {
        status = wcserr_set(WCS_ERRMSG(WCSERR_NON_SEPARABLE));
        goto cleanup;
d968 1
a968 1
  if (itmp) free(itmp);
@


4.22.1.3
log
@New function wcscompare() contributed by Michael Droettboom.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.22.1.2 2014/05/10 14:26:56 mcalabre Exp mcalabre $
a517 1
  wcs->velangl    = UNDEFINED;
a977 142
}

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

int wcscompare(
  int cmp,
  const struct wcsprm *wcs1,
  const struct wcsprm *wcs2,
  int *equal)

{
  int i, j, naxis, naxis2;
  double diff;
  int tab_equal;
  int status;

  if (wcs1  == 0x0) return WCSERR_NULL_POINTER;
  if (wcs2  == 0x0) return WCSERR_NULL_POINTER;
  if (equal == 0x0) return WCSERR_NULL_POINTER;

  *equal = 0;

  if (wcs1->naxis != wcs2->naxis) {
    return 0;
  }

  naxis = wcs1->naxis;
  naxis2 = wcs1->naxis*wcs1->naxis;

  if (cmp & WCSCOMPARE_CRPIX) {
    /* Don't compare crpix. */
  } else if (cmp & WCSCOMPARE_TILING) {
    for (i = 0; i < naxis; ++i) {
      diff = wcs1->crpix[i] - wcs2->crpix[i];
      if ((double)(int)(diff) != diff) {
        return 0;
      }
    }
  } else {
    if (!wcsutil_Eq(naxis, wcs1->crpix, wcs2->crpix)) {
      return 0;
    }
  }

  if (!wcsutil_Eq(naxis2, wcs1->pc, wcs2->pc) ||
      !wcsutil_Eq(naxis, wcs1->cdelt, wcs2->cdelt) ||
      !wcsutil_Eq(naxis, wcs1->crval, wcs2->crval) ||
      !wcsutil_strEq(naxis, wcs1->cunit, wcs2->cunit) ||
      !wcsutil_strEq(naxis, wcs1->ctype, wcs2->ctype) ||
      wcs1->lonpole != wcs2->lonpole ||
      wcs1->latpole != wcs2->latpole ||
      wcs1->restfrq != wcs2->restfrq ||
      wcs1->restwav != wcs2->restwav ||
      wcs1->npv != wcs2->npv ||
      wcs1->nps != wcs2->nps) {
    return 0;
  }

  /* Compare pv cards, which may not be in the same order */
  for (i = 0; i < wcs1->npv; ++i) {
    for (j = 0; j < wcs2->npv; ++j) {
      if (wcs1->pv[i].i == wcs2->pv[j].i &&
          wcs1->pv[i].m == wcs2->pv[j].m) {
        if (wcs1->pv[i].value != wcs2->pv[j].value) {
          return 0;
        }
        break;
      }
    }
    /* We didn't find a match, so they are not equal */
    if (j == wcs2->npv) {
      return 0;
    }
  }

  /* Compare ps cards, which may not be in the same order */
  for (i = 0; i < wcs1->nps; ++i) {
    for (j = 0; j < wcs2->nps; ++j) {
      if (wcs1->ps[i].i == wcs2->ps[j].i &&
          wcs1->ps[i].m == wcs2->ps[j].m) {
        if (strncmp(wcs1->ps[i].value, wcs2->ps[j].value, 72)) {
          return 0;
        }
        break;
      }
    }
    /* We didn't find a match, so they are not equal */
    if (j == wcs2->nps) {
      return 0;
    }
  }

  if (wcs1->flag != WCSSET || wcs2->flag != WCSSET) {
    if (!wcsutil_Eq(naxis2, wcs1->cd, wcs2->cd) ||
        !wcsutil_Eq(naxis, wcs1->crota, wcs2->crota) ||
        wcs1->altlin != wcs2->altlin ||
        wcs1->velref != wcs2->velref) {
      return 0;
    }
  }

  if (!(cmp & WCSCOMPARE_ANCILLARY)) {
    if (strncmp(wcs1->alt, wcs2->alt, 4) ||
        wcs1->colnum != wcs2->colnum ||
        !wcsutil_intEq(naxis, wcs1->colax, wcs2->colax) ||
        !wcsutil_strEq(naxis, wcs1->cname, wcs2->cname) ||
        !wcsutil_Eq(naxis, wcs1->crder, wcs2->crder) ||
        !wcsutil_Eq(naxis, wcs1->csyer, wcs2->csyer) ||
        strncmp(wcs1->dateavg, wcs2->dateavg, 72) ||
        strncmp(wcs1->dateobs, wcs2->dateobs, 72) ||
        wcs1->equinox != wcs2->equinox ||
        wcs1->mjdavg != wcs2->mjdavg ||
        wcs1->mjdobs != wcs2->mjdobs ||
        !wcsutil_Eq(3, wcs1->obsgeo, wcs2->obsgeo) ||
        strncmp(wcs1->radesys, wcs2->radesys, 72) ||
        strncmp(wcs1->specsys, wcs2->specsys, 72) ||
        strncmp(wcs1->ssysobs, wcs2->ssysobs, 72) ||
        wcs1->velosys != wcs2->velosys ||
        wcs1->zsource != wcs2->zsource ||
        strncmp(wcs1->ssyssrc, wcs2->ssyssrc, 72) ||
        wcs1->velangl != wcs2->velangl ||
        strncmp(wcs1->wcsname, wcs2->wcsname, 72)) {
      return 0;
    }
  }

  /* Compare tabular parameters */
  if (wcs1->ntab != wcs2->ntab) {
    return 0;
  }

  for (i = 0; i < wcs1->ntab; ++i) {
    if ((status = tabcmp(0, &wcs1->tab[i], &wcs2->tab[i], &tab_equal))) {
      return status;
    }
    if (!tab_equal) {
      return 0;
    }
  }

  *equal = 1;
  return 0;
@


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: wcs.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: wcs.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: wcs.c,v 4.19.1.3 2013/12/17 14:55:10 mcalabre Exp mcalabre $
@


4.20.1.1
log
@WCSLIB 4.20 development branch.
@
text
@d25 1
a25 1
  $Id: wcs.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: wcs.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: wcs.c,v 4.18.1.2 2013/09/29 10:22:01 mcalabre Exp mcalabre $
d1486 18
d2058 1
a2058 1
          "In CUNIT%d%.1s: %s", i, (*wcs->alt)?wcs->alt:"", uniterr->msg);
@


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


4.19.1.2
log
@Added function wcsbchk() to control strict bounds checking in the
projection routines.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.19.1.1 2013/09/29 14:20:38 mcalabre Exp mcalabre $
a1479 18

  return 0;
}

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

int wcsbchk(struct wcsprm *wcs, int bounds)

{
  int status;

  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  if (wcs->flag != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  wcs->cel.prj.bounds = bounds;
@


4.19.1.3
log
@Fixed an incorrect error message in wcs_units() (from Michael Droettboom).
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.19.1.2 2013/12/10 23:07:23 mcalabre Exp mcalabre $
d2058 1
a2058 1
          "In CUNIT%d%.1s: %s", i+1, (*wcs->alt)?wcs->alt:"", uniterr->msg);
@


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: wcs.c,v 4.17.1.1 2013/01/29 05:32:32 cal103 Exp cal103 $
d559 1
d839 6
a844 2
    if (i == 0 || (i > 0 && map[i-1])) {
      /* i == 0 is a special code for the latitude axis. */
@


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


4.18.1.2
log
@Bug fix in wcssub() when copying parameter values for PROJPn keywords which
have i == 0 (reported by Paul Price).  Also check that wcsdst is non-zero.
@
text
@d25 1
a25 1
  $Id: wcs.c,v 4.18.1.1 2013/07/13 10:02:37 mcalabre Exp mcalabre $
a558 1
  if (wcsdst == 0x0) return WCSERR_NULL_POINTER;
d838 2
a839 6
    if (i == 0) {
      /* i == 0 is a special code that means "the latitude axis". */
      wcsdst->pv[npv] = wcssrc->pv[k];
      wcsdst->pv[npv].i = 0;
      npv++;
    } else if (i > 0 && map[i-1]) {
@


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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.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: wcs.c,v 4.13.1.2 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: wcs.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: wcs.c,v 4.12.1.2 2012/03/14 06:43:15 cal103 Exp cal103 $
@


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


4.13.1.2
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: wcs.c,v 4.13.1.1 2012/03/14 07:40:37 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: wcs.c,v 4.11.1.1 2012/02/20 23:31:13 cal103 Exp cal103 $
d151 1
a151 1
  if (naxis <= 0) {
d153 1
a153 1
      "naxis must be positive (got %d)", naxis);
d713 1
a713 1
    status = 0;
d1071 4
a1074 2
  if (wcs->err) free(wcs->err);
  wcs->err = 0x0;
d3228 1
@


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


4.12.1.2
log
@In wcsini(), allow naxis to be zero for a completely degenerate coordinate
system as may be produced by wcssub().  In wcssub(), ensure that wcsini()
is called for a completely degenerate coordinate system with naxis == 0.
In wcssptr(), call spcfree() before spcini() to plug a memory leak.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.12.1.1 2012/02/29 07:59:10 cal103 Exp cal103 $
d151 1
a151 1
  if (naxis < 0) {
d153 1
a153 1
      "naxis must not be negative (got %d)", naxis);
d713 1
a713 1
    status = wcsini(alloc, 0, wcsdst);
d1071 2
a1072 4
  if (wcs->err) {
    free(wcs->err);
    wcs->err = 0x0;
  }
a3225 1
  spcfree(&(wcs->spc));
@


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: wcs.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: wcs.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: wcs.c,v 4.9.1.2 2012/01/31 23:56:50 cal103 Exp cal103 $
@


4.10.1.1
log
@WCSLIB 4.10 development branch.
@
text
@d31 1
a31 1
  $Id: wcs.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: wcs.c,v 4.8.1.3 2012/01/24 05:23:06 cal103 Exp cal103 $
d702 4
d722 5
a726 1
  /* Construct the inverse axis map. */
d732 3
a734 1
    map[axes[i]-1] = i+1;
d786 5
a790 3
  for (j = 0; j < *nsub; j++) {
    k = axes[j] - 1;
    *(dstp++) = *(srcp+k);
d796 7
a802 3
    for (j = 0; j < *nsub; j++) {
      k = (axes[i]-1)*naxis + (axes[j]-1);
      *(dstp++) = *(srcp+k);
d808 5
a812 3
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    *(dstp++) = *(srcp+k);
d818 5
a822 3
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    *(dstp++) = *(srcp+k);
d827 5
a831 3
    k = axes[i] - 1;
    strncpy(wcsdst->cunit[i], wcssrc->cunit[k], 72);
    strncpy(wcsdst->ctype[i], wcssrc->ctype[k], 72);
d868 7
a874 3
    for (j = 0; j < *nsub; j++) {
      k = (axes[i]-1)*naxis + (axes[j]-1);
      *(dstp++) = *(srcp+k);
d880 5
a884 3
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    *(dstp++) = *(srcp+k);
d896 7
a902 5
    k = axes[i] - 1;
    wcsdst->colax[i] = wcssrc->colax[k];
    strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
    wcsdst->crder[i] = wcssrc->crder[k];
    wcsdst->csyer[i] = wcssrc->csyer[k];
d1807 1
a1807 1
    /* Translate AIPS spectral types. */
@


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


4.9.1.2
log
@Gave wcssub() the ability to add new axes to a wcsprm.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.9.1.1 2012/01/24 05:41:45 cal103 Exp cal103 $
a701 4
    } else if (axis == 0) {
      /* Graft on a new axis. */
      map[msub++] = 0;

d718 1
a718 5
  /* Construct the inverse axis map:
     axes[i] == j means that output axis i+1 comes from input axis j,
     axes[i] == 0 means to create a new axis,
      map[i] == j means that input axis i+1 goes to output axis j,
      map[i] == 0 means that input axis i+1 is not used. */
d724 1
a724 3
    if (axes[i] > 0) {
      map[axes[i]-1] = i+1;
    }
d776 3
a778 5
  for (j = 0; j < *nsub; j++, dstp++) {
    if (axes[j] > 0) {
      k = axes[j] - 1;
      *dstp = *(srcp+k);
    }
d784 3
a786 7
    if (axes[i] > 0) {
      for (j = 0; j < *nsub; j++, dstp++) {
        if (axes[j] > 0) {
          k = (axes[i]-1)*naxis + (axes[j]-1);
          *dstp = *(srcp+k);
        }
      }
d792 3
a794 5
  for (i = 0; i < *nsub; i++, dstp++) {
    if (axes[i] > 0) {
      k = axes[i] - 1;
      *dstp = *(srcp+k);
    }
d800 3
a802 5
  for (i = 0; i < *nsub; i++, dstp++) {
    if (axes[i] > 0) {
      k = axes[i] - 1;
      *dstp = *(srcp+k);
    }
d807 3
a809 5
    if (axes[i] > 0) {
      k = axes[i] - 1;
      strncpy(wcsdst->cunit[i], wcssrc->cunit[k], 72);
      strncpy(wcsdst->ctype[i], wcssrc->ctype[k], 72);
    }
d846 3
a848 7
    if (axes[i] > 0) {
      for (j = 0; j < *nsub; j++, dstp++) {
        if (axes[j] > 0) {
          k = (axes[i]-1)*naxis + (axes[j]-1);
          *dstp = *(srcp+k);
        }
      }
d854 3
a856 5
  for (i = 0; i < *nsub; i++, dstp++) {
    if (axes[i] > 0) {
      k = axes[i] - 1;
      *dstp = *(srcp+k);
    }
d868 5
a872 7
    if (axes[i] > 0) {
      k = axes[i] - 1;
      wcsdst->colax[i] = wcssrc->colax[k];
      strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
      wcsdst->crder[i] = wcssrc->crder[k];
      wcsdst->csyer[i] = wcssrc->csyer[k];
    }
d1777 1
a1777 1
    /* Translate AIPS spectral types for spctyp(). */
@


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: wcs.c,v 4.7.1.7 2011/08/12 05:42:29 cal103 Exp cal103 $
d1323 1
a1323 1
    wcserr_prt(wcs->err, "");
@


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


4.8.1.2
log
@Minor refinement in wcsprt() for printing wcsprm::err.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.8.1.1 2011/08/15 08:07:06 cal103 Exp cal103 $
d1323 1
a1323 1
    wcserr_prt(wcs->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: wcs.c,v 4.8.1.2 2011/11/17 03:10:27 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: wcs.c,v 4.6.1.4 2011/01/27 00:27:00 cal103 Exp cal103 $
d39 1
a47 1
#include "spx.h"
d77 3
d84 3
a86 3
/* Internal helper functions, not intended for general use. */
int  wcs_types(struct wcsprm *);
int  wcs_units(struct wcsprm *);
d98 2
d102 3
d106 14
a119 1
  if (wcs == 0x0) return 1;
a120 3
  if (naxis <= 0) {
    return 2;
  }
d122 1
a122 1
  /* Initialize memory management. */
d124 7
d149 1
d151 3
a153 3
    if (wcs->flag == -1) {
      wcs->lin.flag = -1;
    }
a155 2
  if (wcs->flag == -1) wcs->types = 0x0;

d191 1
a191 1
          return 2;
d208 1
a208 1
          return 2;
d225 1
a225 1
          return 2;
d242 1
a242 1
          return 2;
d259 1
a259 1
          return 2;
d276 1
a276 1
          return 2;
d294 1
a294 1
            return 2;
d317 1
a317 1
            return 2;
d339 1
a339 1
          return 2;
d356 1
a356 1
          return 2;
d373 1
a373 1
          return 2;
d390 1
a390 1
          return 2;
d407 1
a407 1
          return 2;
d424 1
a424 1
          return 2;
d445 1
a445 1
    return status;
d554 2
d562 1
d564 2
a565 1
  if (wcssrc == 0x0) return 1;
d568 2
a569 1
    return 2;
d573 1
a573 1
    return 2;
d587 1
a587 1
      return 2;
d595 3
d703 1
a703 1
      status = 12;
d735 1
a735 1
          status = 13;
d913 1
a913 1
      status = 2;
d927 1
d956 1
a956 1
  if (wcs == 0x0) return 1;
d1041 8
a1048 1
  return linfree(&(wcs->lin));
d1059 1
a1059 1
  if (wcs == 0x0) return 1;
d1068 1
a1068 1
  wcsprintf("      crpix: %p\n", (void *)wcs->crpix);
d1077 1
a1077 1
  wcsprintf("         pc: %p\n", (void *)wcs->pc);
d1087 1
a1087 1
  wcsprintf("      cdelt: %p\n", (void *)wcs->cdelt);
d1095 1
a1095 1
  wcsprintf("      crval: %p\n", (void *)wcs->crval);
d1103 1
a1103 1
  wcsprintf("      cunit: %p\n", (void *)wcs->cunit);
d1108 1
a1108 1
  wcsprintf("      ctype: %p\n", (void *)wcs->ctype);
d1126 1
a1126 1
  wcsprintf("         pv: %p\n", (void *)wcs->pv);
d1133 1
a1133 1
  wcsprintf("         ps: %p\n", (void *)wcs->ps);
d1141 1
a1141 1
  wcsprintf("         cd: %p\n", (void *)wcs->cd);
d1152 1
a1152 1
  wcsprintf("      crota: %p\n", (void *)wcs->crota);
d1170 1
a1170 1
  wcsprintf("      colax: %p\n", (void *)wcs->colax);
d1185 1
a1185 1
  wcsprintf("      cname: %p\n", (void *)wcs->cname);
d1196 1
a1196 1
  wcsprintf("      crder: %p\n", (void *)wcs->crder);
d1209 1
a1209 1
  wcsprintf("      csyer: %p\n", (void *)wcs->csyer);
d1299 1
a1299 1
  wcsprintf("        tab: %p", (void *)wcs->tab);
d1303 1
a1303 1
  wcsprintf("        wtb: %p", (void *)wcs->wtb);
d1308 1
a1308 1
  wcsprintf("      types: %p\n           ", (void *)wcs->types);
d1321 5
d1333 1
a1333 1
  wcsprintf("    m_crpix: %p", (void *)wcs->m_crpix);
d1336 1
a1336 1
  wcsprintf("       m_pc: %p", (void *)wcs->m_pc);
d1339 1
a1339 1
  wcsprintf("    m_cdelt: %p", (void *)wcs->m_cdelt);
d1342 1
a1342 1
  wcsprintf("    m_crval: %p", (void *)wcs->m_crval);
d1345 1
a1345 1
  wcsprintf("    m_cunit: %p", (void *)wcs->m_cunit);
d1348 1
a1348 1
  wcsprintf("    m_ctype: %p", (void *)wcs->m_ctype);
d1351 1
a1351 1
  wcsprintf("       m_pv: %p", (void *)wcs->m_pv);
d1354 1
a1354 1
  wcsprintf("       m_ps: %p", (void *)wcs->m_ps);
d1357 1
a1357 1
  wcsprintf("       m_cd: %p", (void *)wcs->m_cd);
d1360 1
a1360 1
  wcsprintf("    m_crota: %p", (void *)wcs->m_crota);
d1364 1
a1364 1
  wcsprintf("    m_colax: %p", (void *)wcs->m_colax);
d1367 1
a1367 1
  wcsprintf("    m_cname: %p", (void *)wcs->m_cname);
d1370 1
a1370 1
  wcsprintf("    m_crder: %p", (void *)wcs->m_crder);
d1373 1
a1373 1
  wcsprintf("    m_csyer: %p", (void *)wcs->m_csyer);
d1376 1
a1376 1
  wcsprintf("      m_tab: %p", (void *)wcs->m_tab);
d1379 1
a1379 1
  wcsprintf("      m_wtb: %p", (void *)wcs->m_wtb);
d1397 3
a1399 3
      wcsprintf("     dimlen: %p\n", (void *)wtbp->dimlen);
      wcsprintf("     arrayp: %p -> %p\n", (void *)wtbp->arrayp,
                                           (void *)(*(wtbp->arrayp)));
d1431 24
d1458 2
d1467 2
d1470 2
a1473 1
  if (wcs == 0x0) return 1;
d1531 3
a1533 1
          return 6;
d1549 2
a1550 1
        return 5;
d1565 1
a1565 1
      return status + 3;
d1599 4
a1602 1
    spctyp(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0, 0x0, 0x0);
d1626 1
a1626 1
      return status + 3;
d1634 1
a1634 1
      return status + 3;
d1660 4
a1663 1
        if (wcs->cdelt[i] == 0.0) return 3;
d1678 1
a1678 1
    return status;
d1700 1
d1705 2
d1710 1
d1713 1
d1715 2
a1716 2

  if (wcs == 0x0) return 1;
d1726 2
d1732 3
d1811 3
a1813 1
          return 4;
d1833 3
a1835 1
        return 4;
d1858 3
a1860 1
        return 4;
d1912 3
a1914 1
        return 4;
d1927 3
a1929 1
        return 4;
d1942 2
a1943 1
    return 4;
d1949 1
d1954 2
a1955 1
        return 4;
d1964 1
d1969 2
d1974 1
d1976 2
a1977 2
  /* Initialize if required. */
  if (wcs == 0x0) return 1;
d2006 6
a2011 2
      if (wcsunits(wcs->cunit[i], units, &scale, &offset, &power)) {
        return 6;
d2047 2
d2055 1
d2058 3
a2060 1
  if (wcs == 0x0) return 1;
d2066 4
a2069 1
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) return 4;
d2074 1
a2074 1
    return status;
d2079 1
a2079 1
    return 2;
d2120 1
a2120 1
            status = 8;
d2145 1
a2145 1
              status = 8;
d2169 2
a2170 2
        if (istat == 5) {
          status = 8;
d2172 1
a2172 1
          status = istat + 3;
d2203 6
a2208 1

d2213 6
a2218 7
      }

      if (istat) {
        if (istat == 3) {
          status = 8;
        } else {
          status = istat + 3;
d2240 2
a2241 2
    if (istat == 4) {
      status = 8;
d2250 2
a2251 1
      status = (istat == 3) ? 5 : istat;
d2282 2
d2291 1
d2295 3
a2297 2
  status = 0;
  if (wcs == 0x0) return 1;
d2303 4
a2306 1
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) return 4;
d2310 1
a2310 1
    return 2;
d2313 1
d2351 2
a2352 2
        if (istat == 6) {
          status = 9;
d2354 1
a2354 1
          status = istat + 3;
d2368 1
a2368 1
      if (istat == 6) {
d2420 6
a2425 1

d2430 5
a2434 7
      }

      if (istat) {
        if (istat == 4) {
          status = 9;
        } else {
          status = istat + 3;
d2456 2
a2457 2
    if (istat == 5) {
      status = 9;
d2466 2
a2467 1
      status = (istat == 3) ? 5 : istat;
d2482 1
a2482 1
    status = istat;
d2507 2
d2523 1
d2526 3
a2528 1
  if (wcs == 0x0) return 1;
d2578 4
a2581 1
        return (status == 9) ? 10 : status;
d2592 4
a2595 1
        return (status == 9) ? 10 : status;
d2622 4
a2625 1
            return (status == 9) ? 10 : status;
d2667 4
a2670 1
              return (status == 9) ? 10 : status;
d2721 4
a2724 1
            return (status == 9) ? 10 : status;
d2733 4
a2736 1
            return (status == 9) ? 10 : status;
d2745 4
a2748 1
              return (status == 9) ? 10 : status;
d2758 4
a2761 1
              return (status == 9) ? 10 : status;
d2795 4
a2798 1
        return (status == 9) ? 10 : status;
d2809 4
a2812 1
        return (status == 9) ? 10 : status;
d2838 4
a2841 1
            return (status == 9) ? 10 : status;
d2883 4
a2886 1
              return (status == 9) ? 10 : status;
d2937 4
a2940 1
            return (status == 9) ? 10 : status;
d2949 4
a2952 1
            return (status == 9) ? 10 : status;
d2961 4
a2964 1
              return (status == 9) ? 10 : status;
d2974 4
a2977 1
              return (status == 9) ? 10 : status;
d3020 1
a3020 1
    status = sphx2s(wcscel->euler, 1, 1, 1, 1, phi, theta, &lng, &lat);
d3045 6
a3050 1
      return (status == 9) ? 10 : status;
d3069 6
a3074 1
        return (status == 9) ? 10 : status;
d3107 6
a3112 1
        return (status == 9) ? 10 : status;
d3137 1
a3137 1
  return 11;
d3148 2
d3152 1
d3155 3
a3157 1
  if (wcs == 0x0) return 1;
d3173 2
a3174 1
        return 12;
d3182 3
a3184 3
  if ((status = spctrn(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                       wcs->restfrq, wcs->restwav, ctype, &crval, &cdelt))) {
    return 6;
@


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


4.7.1.2
log
@In wcssub(), ensure that wcstab->m_tab has been initialized before trying
to free it on status return 12 or 13.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.7.1.1 2011/02/07 07:04:22 cal103 Exp cal103 $
a565 3
  /* So that we don't try to free an uninitialized pointer on cleanup. */
  wcsdst->m_tab = 0x0;

@


4.7.1.3
log
@Added error messaging based on wcserr.  Changes supplied by Michael
Droettboom (STScI) with respect to the released WCSLIB 4.7 sources.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.7 2011/02/07 07:03:42 cal103 Exp $
d98 1
a98 3
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  wcserr_ini(&wcs->err);
d101 1
a101 3
    return WCSERR_SET(
      &wcs->err, WCSERR_MEMORY,
      "naxis must be positive (got %d)", naxis);
d167 1
a167 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d184 1
a184 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d201 1
a201 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d218 1
a218 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d235 1
a235 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d252 1
a252 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d270 1
a270 1
            return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d293 1
a293 1
            return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d315 1
a315 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d332 1
a332 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d349 1
a349 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d366 1
a366 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d383 1
a383 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d400 1
a400 1
          return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d421 1
a421 1
    return wcserr_copy(&(wcs->err), &(wcs->lin.err));
d537 1
a537 1
  if (wcssrc == 0x0) return WCSERR_NULL_POINTER;
d540 1
a540 3
    return WCSERR_SET(
      &wcsdst->err, WCSERR_MEMORY,
      "naxis must be positive (got %d)", naxis);
d544 1
a544 1
    return WCSERR_SET(&wcsdst->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d558 1
a558 1
      return WCSERR_SET(&wcsdst->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d566 3
d674 1
a674 2
      status = WCSERR_SET(
        &wcsdst->err, WCSERR_BAD_SUBIMAGE, wcs_errmsg[WCSERR_BAD_SUBIMAGE]);
d706 1
a706 2
          status = WCSERR_SET(
            &wcsdst->err, WCSERR_NON_SEPARABLE, wcs_errmsg[WCSERR_NON_SEPARABLE]);
d883 2
a884 1
      return WCSERR_SET(&wcsdst->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
a897 1
          wcserr_copy(&wcsdst->err, &((wcssrc->tab + itab)->err));
d926 1
a926 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
a1010 2
  wcserr_ini(&wcs->err);

d1022 1
a1022 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
a1400 2
  if (wcs == 0x0) return WCSERR_NULL_POINTER;

d1402 1
d1460 1
a1460 5
          /* ERRTODO: Better message */
          return WCSERR_SET(
            &wcs->err, WCSERR_BAD_COORD_TRANS,
            "PV%i_%i%s: Bad coordinate transformation parameter",
            i+1, m, wcs->alt);
d1476 1
a1476 4
        /* ERRTODO: Better message */
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_PARAM,
          "Invalid parameter value");
d1491 1
a1491 3
      wcserr_copy(&wcs->err, &wcscel->err);
      wcs->err.status += 3;
      return wcs->err.status;
d1525 1
a1525 5
    if ((status =
         spctyp_err(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0, 0x0,
                    0x0, &wcs->err))) {
      return status;
    }
d1549 1
a1549 3
      wcserr_copy(&wcs->err, &wcsspc->err);
      wcs->err.status += 3;
      return wcs->err.status;
d1557 1
a1557 3
      wcserr_copy(&wcs->err, &((wcs->tab + j)->err));
      wcs->err.status += 3;
      return wcs->err.status;
d1583 1
a1583 5
        if (wcs->cdelt[i] == 0.0) {
          return WCSERR_SET(
            &wcs->err, WCSERR_SINGULAR_MTX,
            "Singular transformation matrix");
        }
d1598 1
a1598 1
    return wcserr_copy(&wcs->err, &(wcs->lin.err));
d1630 2
a1631 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
a1644 3
  if (wcs->types == NULL) {
    return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
  }
d1721 1
a1721 4
          return WCSERR_SET(
            &wcs->err, WCSERR_BAD_CTYPE,
            "Multiple CUBEFACE axes (in CTYPE%d%s and CTYPE%d%s)",
            wcs->cubeface, wcs->alt, i, wcs->alt);
d1741 1
a1741 4
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_CTYPE,
          "Multiple spectral axes (in CTYPE%d%s and CTYPE%d%s)",
          wcs->spec, wcs->alt, i, wcs->alt);
d1764 1
a1764 4
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_CTYPE,
          "Unrecognized projection code (%s in CTYPE%d%s)",
          ctypei+5, i, wcs->alt);
d1816 1
a1816 4
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_CTYPE,
          "Unrecognized celestial type (%5s in CTYPE%d%s)",
          ctypei, i, wcs->alt);
d1829 1
a1829 4
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_CTYPE,
          "Inconsistent projection types (expected %s, got %s in CTYPE%d%s)",
          requir, ctypei, i, wcs->alt);
d1842 1
a1842 3
    return WCSERR_SET(
      &wcs->err, WCSERR_BAD_CTYPE,
      "Unmatched celestial axes");
a1851 1
        /* ERRTODO: How to handle this? */
a1867 3
  struct wcserr uniterr;
  
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
d1869 3
a1871 2
  wcserr_ini(&uniterr);
  
d1899 2
a1900 4
      if (wcsunits_err(wcs->cunit[i], units, &scale, &offset, &power, &uniterr)) {
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_COORD_TRANS,
          "In CUNIT%d%s: %s", i, wcs->alt, uniterr.msg);
d1944 1
a1944 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
d1950 1
a1950 5
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) {
    return WCSERR_SET(
      &wcs->err, WCSERR_BAD_CTYPE,
      "ncoord and/or nelem inconsistent with the wcsprm");                
  }
d1955 1
a1955 1
    return wcserr_copy(&wcs->err, &(wcs->lin.err));
d1960 1
a1960 1
    return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d2001 1
a2001 1
            status = WCSERR_BAD_PIX;
d2026 1
a2026 1
              status = WCSERR_BAD_PIX;
d2050 2
a2051 2
        if (istat == CELERR_BAD_PIX) {
          status = WCSERR_BAD_PIX;
d2084 1
a2084 7
        if (istat == SPCERR_BAD_X) {
          status = WCSERR_BAD_PIX;
        } else if (istat) {
          wcserr_copy(&wcs->err, &wcs->spc.err);
          wcs->err.status = status = istat + 3;
          goto cleanup;
        }
d2089 7
a2095 4
        if (istat == LOGERR_BAD_X) {
          status = WCSERR_BAD_PIX;
        } else if (istat == LOGERR_BAD_LOG_REF_VAL) {
          status = WCSERR_SET(&wcs->err, WCSERR_BAD_PARAM, log_errmsg[istat]);
d2117 2
a2118 2
    if (istat == TABERR_BAD_X) {
      status = WCSERR_BAD_PIX;
d2127 1
a2127 2
      wcserr_copy(&wcs->err, &((wcs->tab + itab)->err));
      wcs->err.status = status = (istat == TABERR_BAD_PARAMS) ? WCSERR_BAD_PARAM : istat;
a2140 4

  if (status == WCSERR_BAD_PIX && wcs->err.msg[0] == 0) {
    WCSERR_SET(&wcs->err, WCSERR_BAD_PIX, wcs_errmsg[WCSERR_BAD_PIX]);
  }
d2169 1
a2169 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
d2175 1
a2175 5
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) {
    return WCSERR_SET(
      &wcs->err, WCSERR_BAD_CTYPE,
      "ncoord and/or nelem inconsistent with the wcsprm");                
  }
d2179 1
a2179 1
    return WCSERR_SET(&wcs->err, WCSERR_MEMORY, wcs_errmsg[WCSERR_MEMORY]);
d2219 2
a2220 2
        if (istat == CELERR_BAD_WORLD) {
          status = WCSERR_BAD_WORLD;
d2236 1
a2236 1
      if (istat == CELERR_BAD_WORLD) {
d2288 1
a2288 7
        if (istat == SPCERR_BAD_SPEC) {
          status = WCSERR_BAD_WORLD;
        } else if (istat) {
          wcserr_copy(&wcs->err, &wcs->spc.err);
          wcs->err.status = status = istat + 3;
          goto cleanup;
        }
d2293 7
a2299 4
        if (istat == LOGERR_BAD_WORLD) {
          status = WCSERR_BAD_WORLD;
        } else if (istat == LOGERR_BAD_LOG_REF_VAL) {
          status = WCSERR_SET(&wcs->err, WCSERR_BAD_PARAM, log_errmsg[istat]);
d2321 2
a2322 2
    if (istat == TABERR_BAD_WORLD) {
      status = WCSERR_BAD_WORLD;
d2331 1
a2331 2
      wcserr_copy(&wcs->err, &((wcs->tab + itab)->err));
      wcs->err.status = status = (istat == TABERR_BAD_PARAMS) ? WCSERR_BAD_PARAM : istat;
d2346 1
a2346 1
    status = wcserr_copy(&wcs->err, &(wcs->lin.err));
a2351 4

  if (status == WCSERR_BAD_WORLD && wcs->err.msg[0] == 0) {
    WCSERR_SET(&wcs->err, WCSERR_BAD_WORLD, wcs_errmsg[WCSERR_BAD_WORLD]);
  }
d2387 1
a2387 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
d2437 1
a2437 3
        wcs->err.status = status = (
          (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
        return status;
d2448 1
a2448 3
        wcs->err.status = status = (
          (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
        return status;
d2475 1
a2475 3
            wcs->err.status = status = (
              (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
            return status;
d2517 1
a2517 3
              wcs->err.status = status = (
                (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
              return status;
d2568 1
a2568 3
            wcs->err.status = status = (
              (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
            return status;
d2577 1
a2577 3
            wcs->err.status = status = (
              (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
            return status;
d2586 1
a2586 3
              wcs->err.status = status = (
                (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
              return status;
d2596 1
a2596 3
              wcs->err.status = status = (
                (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
              return status;
d2630 1
a2630 3
        wcs->err.status = status = (
          (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
        return status;
d2641 1
a2641 3
        wcs->err.status = status = (
          (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
        return status;
d2667 1
a2667 3
            wcs->err.status = status = (
              (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
            return status;
d2709 1
a2709 3
              wcs->err.status = status = (
                (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
              return status;
d2760 1
a2760 3
            wcs->err.status = status = (
              (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
            return status;
d2769 1
a2769 3
            wcs->err.status = status = (
              (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
            return status;
d2778 1
a2778 3
              wcs->err.status = status = (
                (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
              return status;
d2788 1
a2788 3
              wcs->err.status = status = (
                (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
              return status;
d2856 1
a2856 3
      wcs->err.status = status = (
        (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
      return status;
d2875 1
a2875 3
        wcs->err.status = status = (
          (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
        return status;
d2908 1
a2908 3
        wcs->err.status = status = (
          (status == WCSERR_BAD_WORLD) ? WCSERR_BAD_WORLD_COORD : status);
        return status;
d2933 1
a2933 1
  return WCSERR_SET(&wcs->err, WCSERR_NO_SOLUTION, wcs_errmsg[WCSERR_NO_SOLUTION]);
d2948 1
a2948 1
  if (wcs == 0x0) return WCSERR_NULL_POINTER;
d2964 1
a2964 3
        return WCSERR_SET(
          &wcs->err, WCSERR_BAD_SUBIMAGE,
          "No spectral axis found.");
d2972 3
a2974 5
  if ((status = spctrn_err(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                           wcs->restfrq, wcs->restwav, ctype, &crval, &cdelt,
                           &wcs->err))) {
    wcs->err.status = WCSERR_BAD_COORD_TRANS;
    return WCSERR_BAD_COORD_TRANS;
@


4.7.1.4
log
@Revised implementation of Michael Droettboom's error messaging system.
Added back the change made at 4.7.1.2.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.7.1.2 2011/06/03 02:05:54 cal103 Exp cal103 $
a38 1
#include "wcserr.h"
d47 1
a76 3
/* Convenience macro for invoking wcserr_set(). */
#define WCS_ERRMSG(status) WCSERR_SET(status), wcs_errmsg[status]

a94 2
  static const char *function = "wcsini";

a96 1
  struct wcserr **err;
d100 1
a100 14
  /* Initialize error message handling. */
  err = &(wcs->err);
  if (wcs->flag != -1) {
    if (wcs->err) free(wcs->err);
    if (wcs->lin.err) free(wcs->lin.err);
    if (wcs->cel.err) free(wcs->cel.err);
    if (wcs->spc.err) free(wcs->spc.err);
    if (wcs->cel.prj.err) free(wcs->cel.prj.err);
  }
  wcs->err = 0x0;
  wcs->lin.err = 0x0;
  wcs->cel.err = 0x0;
  wcs->spc.err = 0x0;
  wcs->cel.prj.err = 0x0;
d102 5
d108 1
a108 1
  /* Initialize pointers. */
a109 7
    if (wcs->flag == -1) {
      wcs->types = 0x0;
      wcs->lin.flag = -1;
      wcs->tab = 0x0;
    }

    /* Initialize memory management. */
d128 4
d134 1
a134 4
  if (naxis <= 0) {
    return wcserr_set(WCSERR_SET(WCSERR_MEMORY),
      "naxis must be positive (got %d)", naxis);
  }
d171 1
a171 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d188 1
a188 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d205 1
a205 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d222 1
a222 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d239 1
a239 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d256 1
a256 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d274 1
a274 1
            return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d297 1
a297 1
            return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d319 1
a319 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d336 1
a336 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d353 1
a353 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d370 1
a370 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d387 1
a387 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d404 1
a404 1
          return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d425 1
a425 1
    return wcserr_set(WCS_ERRMSG(status));
a533 2
  static const char *function = "wcssub";

a539 1
  struct wcserr **err;
a541 1
  err = &(wcsdst->err);
d544 2
a545 1
    return wcserr_set(WCSERR_SET(WCSERR_MEMORY),
d550 1
a550 1
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d564 1
a564 1
      return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
a571 3
  /* So that we don't try to free an uninitialized pointer on cleanup. */
  wcsdst->m_tab = 0x0;

d677 2
a678 1
      status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_SUBIMAGE));
d710 2
a711 1
          status = wcserr_set(WCS_ERRMSG(WCSERR_NON_SEPARABLE));
d888 1
a888 2

      status = wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d902 1
a902 1
          wcserr_set(WCS_ERRMSG(status));
d1016 1
a1016 2
  if (wcs->err) free(wcs->err);
  wcs->err = 0x0;
d1018 1
a1018 5
  linfree(&(wcs->lin));
  celfree(&(wcs->cel));
  spcfree(&(wcs->spc));

  return 0;
a1290 5
  wcsprintf("        err: %p\n", (void *)wcs->err);
  if (wcs->err) {
    wcserr_prt(wcs->err, "");
  }

a1395 23
int wcsperr(const struct wcsprm *wcs, const char *prefix)

{
  int j;

  if (wcs == 0x0) return WCSERR_NULL_POINTER;

  wcserr_prt(wcs->err, prefix);
  wcserr_prt(wcs->lin.err, prefix);
  wcserr_prt(wcs->cel.err, prefix);
  wcserr_prt(wcs->cel.prj.err, prefix);
  wcserr_prt(wcs->spc.err, prefix);
  if (wcs->tab) {
    for (j = 0; j < wcs->ntab; j++) {
      wcserr_prt((wcs->tab + j)->err, prefix);
    }
  }

  return 0;
}

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

a1398 2
  static const char *function = "wcsset";

a1405 1
  struct wcserr **err;
a1408 1
  err = &(wcs->err);
d1468 4
a1471 2
          return wcserr_set(WCSERR_SET(WCSERR_BAD_COORD_TRANS),
            "PV%i_%i%s: Unrecognized coordinate transformation parameter",
d1488 4
a1491 2
        return wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
          "Invalid projection: NCP blows up on the equator");
d1506 3
a1508 1
      return wcserr_set(WCS_ERRMSG(status+3));
d1542 3
a1544 2
    if ((status = spctype(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0,
                          0x0, 0x0, err))) {
d1570 3
a1572 1
      return wcserr_set(WCS_ERRMSG(status+3));
d1580 3
a1582 1
      return wcserr_set(WCS_ERRMSG(status+3));
d1609 2
a1610 1
          return wcserr_set(WCSERR_SET(WCSERR_SINGULAR_MTX),
d1627 1
a1627 1
    return wcserr_set(WCS_ERRMSG(status));
a1648 1
/*--------------------------------------------------------------------------*/
a1652 2
  static const char *function = "wcs_types";

a1655 1
  const char *alt = "";
a1657 1
  struct wcserr **err;
a1659 1
  err = &(wcs->err);
a1668 2
  if (*(wcs->alt) != ' ') alt = wcs->alt;

d1674 1
a1674 1
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d1752 4
a1755 3
          return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
            "Multiple CUBEFACE axes (in CTYPE%d%.1s and CTYPE%d%.1s)",
            wcs->cubeface, alt, i, alt);
d1775 4
a1778 3
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Multiple spectral axes (in CTYPE%d%.1s and CTYPE%d%.1s)",
          wcs->spec, alt, i, alt);
d1801 4
a1804 3
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Unrecognized projection code (%s in CTYPE%d%.1s)",
          ctypei+5, i, alt);
d1856 4
a1859 3
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Unrecognized celestial type (%5s in CTYPE%d%.1s)",
          ctypei, i, alt);
d1872 4
a1875 3
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE), "Inconsistent "
          "projection types (expected %s, got %s in CTYPE%d%.1s)", requir,
          ctypei, i, alt);
d1888 2
a1889 1
    return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
a1895 1
      /* Get image axis number. */
d1900 2
a1901 2
        return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
          "Table parameters set for non-table axis type");
a1909 1
/*--------------------------------------------------------------------------*/
a1913 2
  static const char *function = "wcs_units";

d1917 2
a1918 2
  struct wcserr *uniterr = 0x0, **err;

a1919 1
  err = &(wcs->err);
d1921 2
d1950 4
a1953 6
      if (wcsunitse(wcs->cunit[i], units, &scale, &offset, &power,
                    &uniterr)) {
        wcserr_set(WCSERR_SET(WCSERR_BAD_COORD_TRANS),
          "In CUNIT%d%.1s: %s", i, (*wcs->alt)?wcs->alt:"", uniterr->msg);
        free(uniterr);
        return WCSERR_BAD_COORD_TRANS;
a1988 2
  static const char *function = "wcsp2s";

a1994 1
  struct wcserr **err;
a1997 2
  err = &(wcs->err);

d2004 3
a2006 2
    return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
      "ncoord and/or nelem inconsistent with the wcsprm");
d2012 1
a2012 1
    return wcserr_set(WCS_ERRMSG(status));
d2017 1
a2017 1
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
d2058 1
a2058 1
            status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
d2083 1
a2083 1
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
d2108 1
a2108 1
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
d2110 1
a2110 1
          status = wcserr_set(WCS_ERRMSG(istat+3));
d2142 1
a2142 1
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
d2144 2
a2145 1
          status = wcserr_set(WCS_ERRMSG(istat+3));
d2153 1
a2153 3
          if (*err == 0x0) {
            wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
          }
d2155 1
a2155 1
          wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM), log_errmsg[istat]);
d2178 1
a2178 1
      status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_PIX));
d2187 2
a2188 2
      if (istat == TABERR_BAD_PARAMS) istat = WCSERR_BAD_PARAM;
      status = wcserr_set(WCS_ERRMSG(istat));
d2202 4
a2222 2
  static const char *function = "wcss2p";

a2229 1
  struct wcserr **err;
d2233 1
a2234 2
  err = &(wcs->err);

d2241 3
a2243 2
    return wcserr_set(WCSERR_SET(WCSERR_BAD_CTYPE),
      "ncoord and/or nelem inconsistent with the wcsprm");
d2248 1
a2248 1
    return wcserr_set(WCS_ERRMSG(WCSERR_MEMORY));
a2250 1
  status = 0;
d2289 1
a2289 1
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
d2291 1
a2291 1
          status = wcserr_set(WCS_ERRMSG(istat+3));
d2358 1
a2358 1
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
d2360 2
a2361 1
          status = wcserr_set(WCS_ERRMSG(istat+3));
d2369 1
a2369 1
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
d2371 1
a2371 2
          status = wcserr_set(WCSERR_SET(WCSERR_BAD_PARAM),
                     log_errmsg[istat]);
d2394 1
a2394 1
      status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD));
d2403 2
a2404 2
      if (istat == TABERR_BAD_PARAMS) istat = WCSERR_BAD_PARAM;
      status = wcserr_set(WCS_ERRMSG(istat));
d2419 1
a2419 1
    status = wcserr_set(WCS_ERRMSG(istat));
d2425 4
a2447 2
  static const char *function = "wcsmix";

a2461 1
  struct wcserr **err;
a2464 2
  err = &(wcs->err);

d2514 2
a2515 3
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
d2527 2
a2528 3
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
d2556 2
a2557 3
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
d2600 2
a2601 3
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
d2653 2
a2654 3
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
d2664 2
a2665 3
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
d2675 2
a2676 3
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
d2687 2
a2688 3
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
d2723 2
a2724 3
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
d2736 2
a2737 3
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
d2764 2
a2765 3
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
d2808 2
a2809 3
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
d2861 2
a2862 3
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
d2872 2
a2873 3
            if (status == WCSERR_BAD_WORLD) {
              status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
            }
d2883 2
a2884 3
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
d2895 2
a2896 3
              if (status == WCSERR_BAD_WORLD) {
                status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
              }
d2940 1
a2940 1
    sphx2s(wcscel->euler, 1, 1, 1, 1, phi, theta, &lng, &lat);
d2965 2
a2966 5
      if (wcs->err) free(wcs->err);
      wcs->err = wcs0.err;
      if (status == WCSERR_BAD_WORLD) {
        status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
      }
d2986 2
a2987 5
        if (wcs->err) free(wcs->err);
        wcs->err = wcs0.err;
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
d3021 2
a3022 5
        if (wcs->err) free(wcs->err);
        wcs->err = wcs0.err;
        if (status == WCSERR_BAD_WORLD) {
          status = wcserr_set(WCS_ERRMSG(WCSERR_BAD_WORLD_COORD));
        }
d3048 1
a3048 1
  return wcserr_set(WCS_ERRMSG(WCSERR_NO_SOLUTION));
a3058 2
  static const char *function = "wcssptr";

a3060 1
  struct wcserr **err;
a3063 2
  err = &(wcs->err);

d3079 2
a3080 1
        return wcserr_set(WCSERR_SET(WCSERR_BAD_SUBIMAGE),
d3089 5
a3093 3
  if (spctrne(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j], wcs->restfrq,
              wcs->restwav, ctype, &crval, &cdelt, &(wcs->spc.err))) {
    return wcserr_set(WCS_ERRMSG(WCSERR_BAD_COORD_TRANS));
@


4.7.1.5
log
@Declared wcs_types() and wcs_units() static.  Amended or augmented several
error messages.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.7.1.4 2011/08/09 02:20:15 cal103 Exp $
d84 3
a86 3
/* Internal helper functions, not for general use. */
static int wcs_types(struct wcsprm *);
static int wcs_units(struct wcsprm *);
d1661 1
a1661 1
            "Singular transformation matrix, CDELT%d is zero", i+1);
d1699 1
a1699 1
/* : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :  */
d1812 1
a1812 1
            wcs->cubeface+1, alt, i+1, alt);
d1834 1
a1834 1
          wcs->spec+1, alt, i+1, alt);
d1859 1
a1859 1
          ctypei+5, i+1, alt);
d1913 1
a1913 1
          ctypei, i+1, alt);
d1928 1
a1928 1
          ctypei, i+1, alt);
d1963 1
a1963 1
/* : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : : :  */
@


4.7.1.6
log
@In wcsperr(), bail out after the first call to wcserr_prt() if wcserr
is not enabled.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.7.1.5 2011/08/10 05:14:13 cal103 Exp cal103 $
d1438 8
a1445 9
  if (!wcserr_prt(wcs->err, prefix)) {
    wcserr_prt(wcs->lin.err, prefix);
    wcserr_prt(wcs->cel.err, prefix);
    wcserr_prt(wcs->cel.prj.err, prefix);
    wcserr_prt(wcs->spc.err, prefix);
    if (wcs->tab) {
      for (j = 0; j < wcs->ntab; j++) {
        wcserr_prt((wcs->tab + j)->err, prefix);
      }
@


4.7.1.7
log
@Use the WCSPRINTF_PTR() macro for printing addresses.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.7.1.6 2011/08/10 05:31:04 cal103 Exp cal103 $
d1068 1
a1068 1
  WCSPRINTF_PTR("      crpix: ", wcs->crpix, "\n");
d1077 1
a1077 1
  WCSPRINTF_PTR("         pc: ", wcs->pc, "\n");
d1087 1
a1087 1
  WCSPRINTF_PTR("      cdelt: ", wcs->cdelt, "\n");
d1095 1
a1095 1
  WCSPRINTF_PTR("      crval: ", wcs->crval, "\n");
d1103 1
a1103 1
  WCSPRINTF_PTR("      cunit: ", wcs->cunit, "\n");
d1108 1
a1108 1
  WCSPRINTF_PTR("      ctype: ", wcs->ctype, "\n");
d1126 1
a1126 1
  WCSPRINTF_PTR("         pv: ", wcs->pv, "\n");
d1133 1
a1133 1
  WCSPRINTF_PTR("         ps: ", wcs->ps, "\n");
d1141 1
a1141 1
  WCSPRINTF_PTR("         cd: ", wcs->cd, "\n");
d1152 1
a1152 1
  WCSPRINTF_PTR("      crota: ", wcs->crota, "\n");
d1170 1
a1170 1
  WCSPRINTF_PTR("      colax: ", wcs->colax, "\n");
d1185 1
a1185 1
  WCSPRINTF_PTR("      cname: ", wcs->cname, "\n");
d1196 1
a1196 1
  WCSPRINTF_PTR("      crder: ", wcs->crder, "\n");
d1209 1
a1209 1
  WCSPRINTF_PTR("      csyer: ", wcs->csyer, "\n");
d1299 1
a1299 1
  WCSPRINTF_PTR("        tab: ", wcs->tab, "");
d1303 1
a1303 1
  WCSPRINTF_PTR("        wtb: ", wcs->wtb, "");
d1308 1
a1308 1
  WCSPRINTF_PTR("      types: ", wcs->types, "\n           ");
d1321 1
a1321 1
  WCSPRINTF_PTR("        err: ", wcs->err, "\n");
d1333 1
a1333 1
  WCSPRINTF_PTR("    m_crpix: ", wcs->m_crpix, "");
d1336 1
a1336 1
  WCSPRINTF_PTR("       m_pc: ", wcs->m_pc, "");
d1339 1
a1339 1
  WCSPRINTF_PTR("    m_cdelt: ", wcs->m_cdelt, "");
d1342 1
a1342 1
  WCSPRINTF_PTR("    m_crval: ", wcs->m_crval, "");
d1345 1
a1345 1
  WCSPRINTF_PTR("    m_cunit: ", wcs->m_cunit, "");
d1348 1
a1348 1
  WCSPRINTF_PTR("    m_ctype: ", wcs->m_ctype, "");
d1351 1
a1351 1
  WCSPRINTF_PTR("       m_pv: ", wcs->m_pv, "");
d1354 1
a1354 1
  WCSPRINTF_PTR("       m_ps: ", wcs->m_ps, "");
d1357 1
a1357 1
  WCSPRINTF_PTR("       m_cd: ", wcs->m_cd, "");
d1360 1
a1360 1
  WCSPRINTF_PTR("    m_crota: ", wcs->m_crota, "");
d1364 1
a1364 1
  WCSPRINTF_PTR("    m_colax: ", wcs->m_colax, "");
d1367 1
a1367 1
  WCSPRINTF_PTR("    m_cname: ", wcs->m_cname, "");
d1370 1
a1370 1
  WCSPRINTF_PTR("    m_crder: ", wcs->m_crder, "");
d1373 1
a1373 1
  WCSPRINTF_PTR("    m_csyer: ", wcs->m_csyer, "");
d1376 1
a1376 1
  WCSPRINTF_PTR("      m_tab: ", wcs->m_tab, "");
d1379 1
a1379 1
  WCSPRINTF_PTR("      m_wtb: ", wcs->m_wtb, "");
d1397 3
a1399 3
      WCSPRINTF_PTR("     dimlen: ", wtbp->dimlen, "\n");
      WCSPRINTF_PTR("     arrayp: ", wtbp->arrayp, " -> ");
      WCSPRINTF_PTR("", *(wtbp->arrayp), "\n");
@


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: wcs.c,v 4.5.1.2 2010/09/23 01:32:16 cal103 Exp cal103 $
d40 1
d443 2
a444 2
  wcs->restfrq =  0.0;
  wcs->restwav =  0.0;
d1022 1
a1022 1
    printf("The wcsprm struct is UNINITIALIZED.\n");
d1026 4
a1029 4
  printf("       flag: %d\n", wcs->flag);
  printf("      naxis: %d\n", wcs->naxis);
  printf("      crpix: %p\n", (void *)wcs->crpix);
  printf("            ");
d1031 1
a1031 1
    printf("  %- 11.5g", wcs->crpix[i]);
d1033 1
a1033 1
  printf("\n");
d1037 1
a1037 1
  printf("         pc: %p\n", (void *)wcs->pc);
d1039 1
a1039 1
    printf("    pc[%d][]:", i);
d1041 1
a1041 1
      printf("  %- 11.5g", wcs->pc[k++]);
d1043 1
a1043 1
    printf("\n");
d1047 2
a1048 2
  printf("      cdelt: %p\n", (void *)wcs->cdelt);
  printf("            ");
d1050 1
a1050 1
    printf("  %- 11.5g", wcs->cdelt[i]);
d1052 1
a1052 1
  printf("\n");
d1055 2
a1056 2
  printf("      crval: %p\n", (void *)wcs->crval);
  printf("            ");
d1058 1
a1058 1
    printf("  %- 11.5g", wcs->crval[i]);
d1060 1
a1060 1
  printf("\n");
d1063 1
a1063 1
  printf("      cunit: %p\n", (void *)wcs->cunit);
d1065 1
a1065 1
    printf("             \"%s\"\n", wcs->cunit[i]);
d1068 1
a1068 1
  printf("      ctype: %p\n", (void *)wcs->ctype);
d1070 1
a1070 1
    printf("             \"%s\"\n", wcs->ctype[i]);
d1075 1
a1075 1
    printf("    lonpole: UNDEFINED\n");
d1077 1
a1077 1
    printf("    lonpole: %9f\n", wcs->lonpole);
d1079 3
a1081 3
  printf("    latpole: %9f\n", wcs->latpole);
  printf("    restfrq: %f\n", wcs->restfrq);
  printf("    restwav: %f\n", wcs->restwav);
d1084 3
a1086 3
  printf("        npv: %d\n", wcs->npv);
  printf("     npvmax: %d\n", wcs->npvmax);
  printf("         pv: %p\n", (void *)wcs->pv);
d1088 1
a1088 1
    printf("             %3d%4d  %- 11.5g\n", (wcs->pv[i]).i,
d1091 3
a1093 3
  printf("        nps: %d\n", wcs->nps);
  printf("     npsmax: %d\n", wcs->npsmax);
  printf("         ps: %p\n", (void *)wcs->ps);
d1095 1
a1095 1
    printf("             %3d%4d  %s\n", (wcs->ps[i]).i,
d1101 1
a1101 1
  printf("         cd: %p\n", (void *)wcs->cd);
d1104 1
a1104 1
      printf("    cd[%d][]:", i);
d1106 1
a1106 1
        printf("  %- 11.5g", wcs->cd[k++]);
d1108 1
a1108 1
      printf("\n");
d1112 1
a1112 1
  printf("      crota: %p\n", (void *)wcs->crota);
d1114 1
a1114 1
    printf("            ");
d1116 1
a1116 1
      printf("  %- 11.5g", wcs->crota[i]);
d1118 1
a1118 1
    printf("\n");
d1121 2
a1122 2
  printf("     altlin: %d\n", wcs->altlin);
  printf("     velref: %d\n", wcs->velref);
d1127 2
a1128 2
  printf("        alt: '%c'\n", wcs->alt[0]);
  printf("     colnum: %d\n", wcs->colnum);
d1130 1
a1130 1
  printf("      colax: %p\n", (void *)wcs->colax);
d1132 1
a1132 1
    printf("           ");
d1134 1
a1134 1
      printf("  %5d", wcs->colax[i]);
d1136 1
a1136 1
    printf("\n");
d1140 1
a1140 1
    printf("    wcsname: UNDEFINED\n");
d1142 1
a1142 1
    printf("    wcsname: \"%s\"\n", wcs->wcsname);
d1145 1
a1145 1
  printf("      cname: %p\n", (void *)wcs->cname);
d1149 1
a1149 1
        printf("             UNDEFINED\n");
d1151 1
a1151 1
        printf("             \"%s\"\n", wcs->cname[i]);
d1156 1
a1156 1
  printf("      crder: %p\n", (void *)wcs->crder);
d1158 1
a1158 1
    printf("           ");
d1161 1
a1161 1
        printf("  UNDEFINED   ");
d1163 1
a1163 1
        printf("  %- 11.5g", wcs->crder[i]);
d1166 1
a1166 1
    printf("\n");
d1169 1
a1169 1
  printf("      csyer: %p\n", (void *)wcs->csyer);
d1171 1
a1171 1
    printf("           ");
d1174 1
a1174 1
        printf("  UNDEFINED   ");
d1176 1
a1176 1
        printf("  %- 11.5g", wcs->csyer[i]);
d1179 1
a1179 1
    printf("\n");
d1183 1
a1183 1
    printf("    radesys: UNDEFINED\n");
d1185 1
a1185 1
    printf("    radesys: \"%s\"\n", wcs->radesys);
d1189 1
a1189 1
    printf("    equinox: UNDEFINED\n");
d1191 1
a1191 1
    printf("    equinox: %9f\n", wcs->equinox);
d1195 1
a1195 1
    printf("    specsys: UNDEFINED\n");
d1197 1
a1197 1
    printf("    specsys: \"%s\"\n", wcs->specsys);
d1201 1
a1201 1
    printf("    ssysobs: UNDEFINED\n");
d1203 1
a1203 1
    printf("    ssysobs: \"%s\"\n", wcs->ssysobs);
d1207 1
a1207 1
    printf("    velosys: UNDEFINED\n");
d1209 1
a1209 1
    printf("    velosys: %9f\n", wcs->velosys);
d1213 1
a1213 1
    printf("    ssyssrc: UNDEFINED\n");
d1215 1
a1215 1
    printf("    ssyssrc: \"%s\"\n", wcs->ssyssrc);
d1219 1
a1219 1
    printf("    zsource: UNDEFINED\n");
d1221 1
a1221 1
    printf("    zsource: %9f\n", wcs->zsource);
d1224 1
a1224 1
  printf("     obsgeo: ");
d1227 1
a1227 1
      printf("UNDEFINED     ");
d1229 1
a1229 1
      printf("%- 11.5g  ", wcs->obsgeo[i]);
d1232 1
a1232 1
  printf("\n");
d1235 1
a1235 1
    printf("    dateobs: UNDEFINED\n");
d1237 1
a1237 1
    printf("    dateobs: \"%s\"\n", wcs->dateobs);
d1241 1
a1241 1
    printf("    dateavg: UNDEFINED\n");
d1243 1
a1243 1
    printf("    dateavg: \"%s\"\n", wcs->dateavg);
d1247 1
a1247 1
    printf("     mjdobs: UNDEFINED\n");
d1249 1
a1249 1
    printf("     mjdobs: %9f\n", wcs->mjdobs);
d1253 1
a1253 1
    printf("     mjdavg: UNDEFINED\n");
d1255 1
a1255 1
    printf("     mjdavg: %9f\n", wcs->mjdavg);
d1258 8
a1265 8
  printf("       ntab: %d\n", wcs->ntab);
  printf("        tab: %p", (void *)wcs->tab);
  if (wcs->tab != 0x0) printf("  (see below)");
  printf("\n");
  printf("       nwtb: %d\n", wcs->nwtb);
  printf("        wtb: %p", (void *)wcs->wtb);
  if (wcs->wtb != 0x0) printf("  (see below)");
  printf("\n");
d1268 1
a1268 1
  printf("      types: %p\n           ", (void *)wcs->types);
d1270 1
a1270 1
    printf("%5d", wcs->types[i]);
d1272 1
a1272 1
  printf("\n");
d1274 10
a1283 10
  printf("     lngtyp: \"%s\"\n", wcs->lngtyp);
  printf("     lattyp: \"%s\"\n", wcs->lattyp);
  printf("        lng: %d\n", wcs->lng);
  printf("        lat: %d\n", wcs->lat);
  printf("       spec: %d\n", wcs->spec);
  printf("   cubeface: %d\n", wcs->cubeface);

  printf("        lin: (see below)\n");
  printf("        cel: (see below)\n");
  printf("        spc: (see below)\n");
d1286 51
a1336 51
  printf("     m_flag: %d\n", wcs->m_flag);
  printf("    m_naxis: %d\n", wcs->m_naxis);
  printf("    m_crpix: %p", (void *)wcs->m_crpix);
  if (wcs->m_crpix == wcs->crpix) printf("  (= crpix)");
  printf("\n");
  printf("       m_pc: %p", (void *)wcs->m_pc);
  if (wcs->m_pc == wcs->pc) printf("  (= pc)");
  printf("\n");
  printf("    m_cdelt: %p", (void *)wcs->m_cdelt);
  if (wcs->m_cdelt == wcs->cdelt) printf("  (= cdelt)");
  printf("\n");
  printf("    m_crval: %p", (void *)wcs->m_crval);
  if (wcs->m_crval == wcs->crval) printf("  (= crval)");
  printf("\n");
  printf("    m_cunit: %p", (void *)wcs->m_cunit);
  if (wcs->m_cunit == wcs->cunit) printf("  (= cunit)");
  printf("\n");
  printf("    m_ctype: %p", (void *)wcs->m_ctype);
  if (wcs->m_ctype == wcs->ctype) printf("  (= ctype)");
  printf("\n");
  printf("       m_pv: %p", (void *)wcs->m_pv);
  if (wcs->m_pv == wcs->pv) printf("  (= pv)");
  printf("\n");
  printf("       m_ps: %p", (void *)wcs->m_ps);
  if (wcs->m_ps == wcs->ps) printf("  (= ps)");
  printf("\n");
  printf("       m_cd: %p", (void *)wcs->m_cd);
  if (wcs->m_cd == wcs->cd) printf("  (= cd)");
  printf("\n");
  printf("    m_crota: %p", (void *)wcs->m_crota);
  if (wcs->m_crota == wcs->crota) printf("  (= crota)");
  printf("\n");
  printf("\n");
  printf("    m_colax: %p", (void *)wcs->m_colax);
  if (wcs->m_colax == wcs->colax) printf("  (= colax)");
  printf("\n");
  printf("    m_cname: %p", (void *)wcs->m_cname);
  if (wcs->m_cname == wcs->cname) printf("  (= cname)");
  printf("\n");
  printf("    m_crder: %p", (void *)wcs->m_crder);
  if (wcs->m_crder == wcs->crder) printf("  (= crder)");
  printf("\n");
  printf("    m_csyer: %p", (void *)wcs->m_csyer);
  if (wcs->m_csyer == wcs->csyer) printf("  (= csyer)");
  printf("\n");
  printf("      m_tab: %p", (void *)wcs->m_tab);
  if (wcs->m_tab == wcs->tab) printf("  (= tab)");
  printf("\n");
  printf("      m_wtb: %p", (void *)wcs->m_wtb);
  if (wcs->m_wtb == wcs->wtb) printf("  (= wtb)");
  printf("\n");
d1341 14
a1354 14
      printf("\n");
      printf("wtb[%d].*\n", j);
      printf("          i: %d\n", wtbp->i);
      printf("          m: %d\n", wtbp->m);
      printf("       kind: %c\n", wtbp->kind);
      printf("     extnam: %s\n", wtbp->extnam);
      printf("     extver: %d\n", wtbp->extver);
      printf("     extlev: %d\n", wtbp->extlev);
      printf("      ttype: %s\n", wtbp->ttype);
      printf("        row: %ld\n", wtbp->row);
      printf("       ndim: %d\n", wtbp->ndim);
      printf("     dimlen: %p\n", (void *)wtbp->dimlen);
      printf("     arrayp: %p -> %p\n", (void *)wtbp->arrayp,
                                        (void *)(*(wtbp->arrayp)));
d1360 2
a1361 2
      printf("\n");
      printf("tab[%d].*\n", j);
d1367 2
a1368 2
  printf("\n");
  printf("   lin.*\n");
d1372 2
a1373 2
  printf("\n");
  printf("   cel.*\n");
d1377 2
a1378 2
  printf("\n");
  printf("   spc.*\n");
@


4.6.1.1
log
@WCSLIB 4.6 development branch.
@
text
@d31 1
a31 1
  $Id: wcs.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: wcs.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: wcs.c,v 4.6.1.2 2011/01/14 06:33:16 cal103 Exp cal103 $
a39 1
#include "wcsprintf.h"
d1021 1
a1021 1
    wcsprintf("The wcsprm struct is UNINITIALIZED.\n");
d1025 4
a1028 4
  wcsprintf("       flag: %d\n", wcs->flag);
  wcsprintf("      naxis: %d\n", wcs->naxis);
  wcsprintf("      crpix: %p\n", (void *)wcs->crpix);
  wcsprintf("            ");
d1030 1
a1030 1
    wcsprintf("  %- 11.5g", wcs->crpix[i]);
d1032 1
a1032 1
  wcsprintf("\n");
d1036 1
a1036 1
  wcsprintf("         pc: %p\n", (void *)wcs->pc);
d1038 1
a1038 1
    wcsprintf("    pc[%d][]:", i);
d1040 1
a1040 1
      wcsprintf("  %- 11.5g", wcs->pc[k++]);
d1042 1
a1042 1
    wcsprintf("\n");
d1046 2
a1047 2
  wcsprintf("      cdelt: %p\n", (void *)wcs->cdelt);
  wcsprintf("            ");
d1049 1
a1049 1
    wcsprintf("  %- 11.5g", wcs->cdelt[i]);
d1051 1
a1051 1
  wcsprintf("\n");
d1054 2
a1055 2
  wcsprintf("      crval: %p\n", (void *)wcs->crval);
  wcsprintf("            ");
d1057 1
a1057 1
    wcsprintf("  %- 11.5g", wcs->crval[i]);
d1059 1
a1059 1
  wcsprintf("\n");
d1062 1
a1062 1
  wcsprintf("      cunit: %p\n", (void *)wcs->cunit);
d1064 1
a1064 1
    wcsprintf("             \"%s\"\n", wcs->cunit[i]);
d1067 1
a1067 1
  wcsprintf("      ctype: %p\n", (void *)wcs->ctype);
d1069 1
a1069 1
    wcsprintf("             \"%s\"\n", wcs->ctype[i]);
d1074 1
a1074 1
    wcsprintf("    lonpole: UNDEFINED\n");
d1076 1
a1076 1
    wcsprintf("    lonpole: %9f\n", wcs->lonpole);
d1078 3
a1080 3
  wcsprintf("    latpole: %9f\n", wcs->latpole);
  wcsprintf("    restfrq: %f\n", wcs->restfrq);
  wcsprintf("    restwav: %f\n", wcs->restwav);
d1083 3
a1085 3
  wcsprintf("        npv: %d\n", wcs->npv);
  wcsprintf("     npvmax: %d\n", wcs->npvmax);
  wcsprintf("         pv: %p\n", (void *)wcs->pv);
d1087 1
a1087 1
    wcsprintf("             %3d%4d  %- 11.5g\n", (wcs->pv[i]).i,
d1090 3
a1092 3
  wcsprintf("        nps: %d\n", wcs->nps);
  wcsprintf("     npsmax: %d\n", wcs->npsmax);
  wcsprintf("         ps: %p\n", (void *)wcs->ps);
d1094 1
a1094 1
    wcsprintf("             %3d%4d  %s\n", (wcs->ps[i]).i,
d1100 1
a1100 1
  wcsprintf("         cd: %p\n", (void *)wcs->cd);
d1103 1
a1103 1
      wcsprintf("    cd[%d][]:", i);
d1105 1
a1105 1
        wcsprintf("  %- 11.5g", wcs->cd[k++]);
d1107 1
a1107 1
      wcsprintf("\n");
d1111 1
a1111 1
  wcsprintf("      crota: %p\n", (void *)wcs->crota);
d1113 1
a1113 1
    wcsprintf("            ");
d1115 1
a1115 1
      wcsprintf("  %- 11.5g", wcs->crota[i]);
d1117 1
a1117 1
    wcsprintf("\n");
d1120 2
a1121 2
  wcsprintf("     altlin: %d\n", wcs->altlin);
  wcsprintf("     velref: %d\n", wcs->velref);
d1126 2
a1127 2
  wcsprintf("        alt: '%c'\n", wcs->alt[0]);
  wcsprintf("     colnum: %d\n", wcs->colnum);
d1129 1
a1129 1
  wcsprintf("      colax: %p\n", (void *)wcs->colax);
d1131 1
a1131 1
    wcsprintf("           ");
d1133 1
a1133 1
      wcsprintf("  %5d", wcs->colax[i]);
d1135 1
a1135 1
    wcsprintf("\n");
d1139 1
a1139 1
    wcsprintf("    wcsname: UNDEFINED\n");
d1141 1
a1141 1
    wcsprintf("    wcsname: \"%s\"\n", wcs->wcsname);
d1144 1
a1144 1
  wcsprintf("      cname: %p\n", (void *)wcs->cname);
d1148 1
a1148 1
        wcsprintf("             UNDEFINED\n");
d1150 1
a1150 1
        wcsprintf("             \"%s\"\n", wcs->cname[i]);
d1155 1
a1155 1
  wcsprintf("      crder: %p\n", (void *)wcs->crder);
d1157 1
a1157 1
    wcsprintf("           ");
d1160 1
a1160 1
        wcsprintf("  UNDEFINED   ");
d1162 1
a1162 1
        wcsprintf("  %- 11.5g", wcs->crder[i]);
d1165 1
a1165 1
    wcsprintf("\n");
d1168 1
a1168 1
  wcsprintf("      csyer: %p\n", (void *)wcs->csyer);
d1170 1
a1170 1
    wcsprintf("           ");
d1173 1
a1173 1
        wcsprintf("  UNDEFINED   ");
d1175 1
a1175 1
        wcsprintf("  %- 11.5g", wcs->csyer[i]);
d1178 1
a1178 1
    wcsprintf("\n");
d1182 1
a1182 1
    wcsprintf("    radesys: UNDEFINED\n");
d1184 1
a1184 1
    wcsprintf("    radesys: \"%s\"\n", wcs->radesys);
d1188 1
a1188 1
    wcsprintf("    equinox: UNDEFINED\n");
d1190 1
a1190 1
    wcsprintf("    equinox: %9f\n", wcs->equinox);
d1194 1
a1194 1
    wcsprintf("    specsys: UNDEFINED\n");
d1196 1
a1196 1
    wcsprintf("    specsys: \"%s\"\n", wcs->specsys);
d1200 1
a1200 1
    wcsprintf("    ssysobs: UNDEFINED\n");
d1202 1
a1202 1
    wcsprintf("    ssysobs: \"%s\"\n", wcs->ssysobs);
d1206 1
a1206 1
    wcsprintf("    velosys: UNDEFINED\n");
d1208 1
a1208 1
    wcsprintf("    velosys: %9f\n", wcs->velosys);
d1212 1
a1212 1
    wcsprintf("    ssyssrc: UNDEFINED\n");
d1214 1
a1214 1
    wcsprintf("    ssyssrc: \"%s\"\n", wcs->ssyssrc);
d1218 1
a1218 1
    wcsprintf("    zsource: UNDEFINED\n");
d1220 1
a1220 1
    wcsprintf("    zsource: %9f\n", wcs->zsource);
d1223 1
a1223 1
  wcsprintf("     obsgeo: ");
d1226 1
a1226 1
      wcsprintf("UNDEFINED     ");
d1228 1
a1228 1
      wcsprintf("%- 11.5g  ", wcs->obsgeo[i]);
d1231 1
a1231 1
  wcsprintf("\n");
d1234 1
a1234 1
    wcsprintf("    dateobs: UNDEFINED\n");
d1236 1
a1236 1
    wcsprintf("    dateobs: \"%s\"\n", wcs->dateobs);
d1240 1
a1240 1
    wcsprintf("    dateavg: UNDEFINED\n");
d1242 1
a1242 1
    wcsprintf("    dateavg: \"%s\"\n", wcs->dateavg);
d1246 1
a1246 1
    wcsprintf("     mjdobs: UNDEFINED\n");
d1248 1
a1248 1
    wcsprintf("     mjdobs: %9f\n", wcs->mjdobs);
d1252 1
a1252 1
    wcsprintf("     mjdavg: UNDEFINED\n");
d1254 1
a1254 1
    wcsprintf("     mjdavg: %9f\n", wcs->mjdavg);
d1257 8
a1264 8
  wcsprintf("       ntab: %d\n", wcs->ntab);
  wcsprintf("        tab: %p", (void *)wcs->tab);
  if (wcs->tab != 0x0) wcsprintf("  (see below)");
  wcsprintf("\n");
  wcsprintf("       nwtb: %d\n", wcs->nwtb);
  wcsprintf("        wtb: %p", (void *)wcs->wtb);
  if (wcs->wtb != 0x0) wcsprintf("  (see below)");
  wcsprintf("\n");
d1267 1
a1267 1
  wcsprintf("      types: %p\n           ", (void *)wcs->types);
d1269 1
a1269 1
    wcsprintf("%5d", wcs->types[i]);
d1271 1
a1271 1
  wcsprintf("\n");
d1273 10
a1282 10
  wcsprintf("     lngtyp: \"%s\"\n", wcs->lngtyp);
  wcsprintf("     lattyp: \"%s\"\n", wcs->lattyp);
  wcsprintf("        lng: %d\n", wcs->lng);
  wcsprintf("        lat: %d\n", wcs->lat);
  wcsprintf("       spec: %d\n", wcs->spec);
  wcsprintf("   cubeface: %d\n", wcs->cubeface);

  wcsprintf("        lin: (see below)\n");
  wcsprintf("        cel: (see below)\n");
  wcsprintf("        spc: (see below)\n");
d1285 51
a1335 51
  wcsprintf("     m_flag: %d\n", wcs->m_flag);
  wcsprintf("    m_naxis: %d\n", wcs->m_naxis);
  wcsprintf("    m_crpix: %p", (void *)wcs->m_crpix);
  if (wcs->m_crpix == wcs->crpix) wcsprintf("  (= crpix)");
  wcsprintf("\n");
  wcsprintf("       m_pc: %p", (void *)wcs->m_pc);
  if (wcs->m_pc == wcs->pc) wcsprintf("  (= pc)");
  wcsprintf("\n");
  wcsprintf("    m_cdelt: %p", (void *)wcs->m_cdelt);
  if (wcs->m_cdelt == wcs->cdelt) wcsprintf("  (= cdelt)");
  wcsprintf("\n");
  wcsprintf("    m_crval: %p", (void *)wcs->m_crval);
  if (wcs->m_crval == wcs->crval) wcsprintf("  (= crval)");
  wcsprintf("\n");
  wcsprintf("    m_cunit: %p", (void *)wcs->m_cunit);
  if (wcs->m_cunit == wcs->cunit) wcsprintf("  (= cunit)");
  wcsprintf("\n");
  wcsprintf("    m_ctype: %p", (void *)wcs->m_ctype);
  if (wcs->m_ctype == wcs->ctype) wcsprintf("  (= ctype)");
  wcsprintf("\n");
  wcsprintf("       m_pv: %p", (void *)wcs->m_pv);
  if (wcs->m_pv == wcs->pv) wcsprintf("  (= pv)");
  wcsprintf("\n");
  wcsprintf("       m_ps: %p", (void *)wcs->m_ps);
  if (wcs->m_ps == wcs->ps) wcsprintf("  (= ps)");
  wcsprintf("\n");
  wcsprintf("       m_cd: %p", (void *)wcs->m_cd);
  if (wcs->m_cd == wcs->cd) wcsprintf("  (= cd)");
  wcsprintf("\n");
  wcsprintf("    m_crota: %p", (void *)wcs->m_crota);
  if (wcs->m_crota == wcs->crota) wcsprintf("  (= crota)");
  wcsprintf("\n");
  wcsprintf("\n");
  wcsprintf("    m_colax: %p", (void *)wcs->m_colax);
  if (wcs->m_colax == wcs->colax) wcsprintf("  (= colax)");
  wcsprintf("\n");
  wcsprintf("    m_cname: %p", (void *)wcs->m_cname);
  if (wcs->m_cname == wcs->cname) wcsprintf("  (= cname)");
  wcsprintf("\n");
  wcsprintf("    m_crder: %p", (void *)wcs->m_crder);
  if (wcs->m_crder == wcs->crder) wcsprintf("  (= crder)");
  wcsprintf("\n");
  wcsprintf("    m_csyer: %p", (void *)wcs->m_csyer);
  if (wcs->m_csyer == wcs->csyer) wcsprintf("  (= csyer)");
  wcsprintf("\n");
  wcsprintf("      m_tab: %p", (void *)wcs->m_tab);
  if (wcs->m_tab == wcs->tab) wcsprintf("  (= tab)");
  wcsprintf("\n");
  wcsprintf("      m_wtb: %p", (void *)wcs->m_wtb);
  if (wcs->m_wtb == wcs->wtb) wcsprintf("  (= wtb)");
  wcsprintf("\n");
d1340 14
a1353 14
      wcsprintf("\n");
      wcsprintf("wtb[%d].*\n", j);
      wcsprintf("          i: %d\n", wtbp->i);
      wcsprintf("          m: %d\n", wtbp->m);
      wcsprintf("       kind: %c\n", wtbp->kind);
      wcsprintf("     extnam: %s\n", wtbp->extnam);
      wcsprintf("     extver: %d\n", wtbp->extver);
      wcsprintf("     extlev: %d\n", wtbp->extlev);
      wcsprintf("      ttype: %s\n", wtbp->ttype);
      wcsprintf("        row: %ld\n", wtbp->row);
      wcsprintf("       ndim: %d\n", wtbp->ndim);
      wcsprintf("     dimlen: %p\n", (void *)wtbp->dimlen);
      wcsprintf("     arrayp: %p -> %p\n", (void *)wtbp->arrayp,
                                           (void *)(*(wtbp->arrayp)));
d1359 2
a1360 2
      wcsprintf("\n");
      wcsprintf("tab[%d].*\n", j);
d1366 2
a1367 2
  wcsprintf("\n");
  wcsprintf("   lin.*\n");
d1371 2
a1372 2
  wcsprintf("\n");
  wcsprintf("   cel.*\n");
d1376 2
a1377 2
  wcsprintf("\n");
  wcsprintf("   spc.*\n");
@


4.6.1.4
log
@Trivial reformatting.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.6.1.3 2011/01/25 00:35:11 cal103 Exp cal103 $
d443 2
a444 2
  wcs->restfrq = 0.0;
  wcs->restwav = 0.0;
@


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: wcs.c,v 4.4.1.5 2010/07/09 07:58:02 cal103 Exp cal103 $
d1465 1
a1465 1
      wcscel->phi0   = wcs->crval[wcs->lng];
@


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


4.5.1.2
log
@When translating GLS to SFL, a non-zero reference longitude introduces an
offset in longitude in the normal way, therefore phi_0 = 0 as usual.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.5.1.1 2010/07/16 07:05:31 cal103 Exp cal103 $
d1465 1
a1465 1
      wcscel->phi0   = 0.0;
@


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: wcs.c,v 4.3.1.5 2009/07/28 07:45:25 cal103 Exp cal103 $
a460 1
  wcs->altlin = 0;
d470 2
d477 1
a809 2
  wcsdst->altlin = wcssrc->altlin;

d826 3
a1098 2
  printf("     altlin: %d\n", wcs->altlin);

d1120 5
d1623 1
a1623 1
  char ctypei[16], pcode[4], requir[9], scode[4];
d1683 5
d1689 1
d1732 2
a1733 2
      /* Spectral axis found (possibly linear, e.g. FREQ-LSR). */
      wcs->types[i] = 3000;
d1735 4
a1738 3
      if (strcmp(scode, "   ") != 0) {
        /* Non-linear spectral axis found. */
        wcs->types[i] += 300;
d1740 1
a1740 7
        /* Check uniqueness. */
        if (wcs->spec >= 0) {
          return 4;
        }

        wcs->spec = i;
      }
a2939 1
  char   *code;
d2949 7
a2955 5
  if ((j = *i) < 0 && (j = wcs->spec) < 0) {
    /* Look for a linear spectral axis. */
    for (j = 0; j < wcs->naxis; j++) {
      if (wcs->types[j]/100 == 30) {
        break;
a2956 1
    }
d2958 4
a2961 3
    if (j >= wcs->naxis) {
      /* No spectral axis. */
      return 12;
d2979 1
d2981 2
a2982 9
  /* Extract the Doppler frame from AIPS-convention types. */
  code = wcs->ctype[j] + 4;
  if (strcmp(code, "-LSR") == 0) {
    strcpy(wcs->specsys, "LSRK");
  } else if (strcmp(code, "-HEL") == 0) {
    strcpy(wcs->specsys, "BARYCENT");
  } else if (strcmp(code, "-OBS") == 0) {
    strcpy(wcs->specsys, "TOPOCENT");
   }
d2984 1
a2984 6
   strcpy(wcs->ctype[j], ctype);

   /* This keeps things tidy if the spectral axis is linear. */
   spcini(&(wcs->spc));

   return 0;
@


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


4.4.1.2
log
@In wcssptr(), ensure that i is always reset if given < 0.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.4.1.1 2009/08/10 08:52:49 cal103 Exp cal103 $
d2943 5
a2947 7
  if ((j = *i) < 0) {
    if ((j = wcs->spec) < 0) {
      /* Look for a linear spectral axis. */
      for (j = 0; j < wcs->naxis; j++) {
        if (wcs->types[j]/100 == 30) {
          break;
        }
d2949 1
d2951 3
a2953 4
      if (j >= wcs->naxis) {
        /* No spectral axis. */
        return 12;
      }
d2980 1
a2980 1
  }
d2982 1
a2982 1
  strcpy(wcs->ctype[j], ctype);
d2984 2
a2985 2
  /* This keeps things tidy if the spectral axis is linear. */
  spcini(&(wcs->spc));
d2987 1
a2987 1
  return 0;
@


4.4.1.3
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2010, Mark Calabretta
d31 1
a31 1
  $Id: wcs.c,v 4.4.1.2 2009/09/03 02:13:43 cal103 Exp cal103 $
@


4.4.1.4
log
@Handle new member, velref, in the wcsprm struct.  In wcs_types(), use
spcaips() to translate AIPS spectral types.
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.4.1.3 2010/01/19 03:42:50 cal103 Exp cal103 $
d461 1
a470 2
  wcs->altlin = 0;
  wcs->velref = 0;
a475 1

d808 2
a825 3
  wcsdst->altlin = wcssrc->altlin;
  wcsdst->velref = wcssrc->velref;

d1096 2
a1118 5
  printf("     altlin: %d\n", wcs->altlin);
  printf("     velref: %d\n", wcs->velref);



d1617 1
a1617 1
  char ctypei[16], pcode[4], requir[9], scode[4], specsys[9];
a1676 4
    /* Translate AIPS spectral types. */
    if (spcaips(ctypei, wcs->velref, ctypei, specsys) == 0) {
      if (wcs->specsys[0] == '\0') strcpy(wcs->specsys, specsys);
    }
a1677 1
    /* Process linear axes. */
d1720 11
a1730 2
      /* Non-linear spectral axis found. */
      wcs->types[i] = 3300;
d1732 1
a1732 3
      /* Check uniqueness. */
      if (wcs->spec >= 0) {
        return 4;
a1734 2
      wcs->spec = i;

d2973 11
@


4.4.1.5
log
@In wcs_types(), need to update wcsprm::ctype after translation by spcaips().
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.4.1.4 2010/07/07 13:26:46 cal103 Exp cal103 $
a1684 1
      strcpy(wcs->ctype[i], ctypei);
d2939 1
@


4.3
log
@WCSLIB 4.3
@
text
@a1 2
    WCSLIB 4.3 - an implementation of the FITS WCS standard.
    Copyright (C) 1995-2007, Mark Calabretta
d3 2
a4 1
    This file is part of WCSLIB.
d6 26
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: wcs.c,v 4.2.1.10 2007/12/03 05:02:17 cal103 Exp cal103 $
d61 14
a74 14
   "Success",
   "Null wcsprm pointer passed",
   "Memory allocation failed",
   "Linear transformation matrix is singular",
   "Inconsistent or unrecognized coordinate axis types",
   "Invalid parameter value",
   "Invalid coordinate transformation parameters",
   "Ill-conditioned coordinate transformation parameters",
   "One or more of the pixel coordinates were invalid",
   "One or more of the world coordinates were invalid",
   "Invalid world coordinate",
   "No solution found in the specified interval",
   "Invalid subimage specification",
   "Non-separable subimage coordinate system"};
d94 2
a95 2
   int i, j, k, status;
   double *cd;
d97 1
a97 1
   if (wcs == 0x0) return 1;
d99 24
a122 3
   if (naxis <= 0) {
      return 2;
   }
d124 4
a127 20
   /* Initialize memory management. */
   if (wcs->flag == -1 || wcs->m_flag != WCSSET) {
      wcs->m_flag  = 0;
      wcs->m_naxis = 0;
      wcs->m_crpix = 0x0;
      wcs->m_pc    = 0x0;
      wcs->m_cdelt = 0x0;
      wcs->m_crval = 0x0;
      wcs->m_cunit = 0x0;
      wcs->m_ctype = 0x0;
      wcs->m_pv    = 0x0;
      wcs->m_ps    = 0x0;
      wcs->m_cd    = 0x0;
      wcs->m_crota = 0x0;
      wcs->m_colax = 0x0;
      wcs->m_cname = 0x0;
      wcs->m_crder = 0x0;
      wcs->m_csyer = 0x0;
      wcs->m_tab   = 0x0;
      wcs->m_wtb   = 0x0;
d129 1
a129 4
      if (wcs->flag == -1) {
         wcs->lin.flag = -1;
      }
   }
a130 1
   if (wcs->flag == -1) wcs->types = 0x0;
d132 31
d164 15
a178 25
   /* Allocate memory for arrays if required. */
   if (alloc ||
       wcs->crpix == 0x0 ||
       wcs->pc    == 0x0 ||
       wcs->cdelt == 0x0 ||
       wcs->crval == 0x0 ||
       wcs->cunit == 0x0 ||
       wcs->ctype == 0x0 ||
       (NPVMAX && wcs->pv == 0x0) ||
       (NPSMAX && wcs->ps == 0x0) ||
       wcs->cd    == 0x0 ||
       wcs->crota == 0x0 ||
       wcs->colax == 0x0 ||
       wcs->cname == 0x0 ||
       wcs->crder == 0x0 ||
       wcs->csyer == 0x0) {

      /* Was sufficient allocated previously? */
      if (wcs->m_flag == WCSSET &&
         (wcs->m_naxis < naxis  ||
          wcs->npvmax  < NPVMAX ||
          wcs->npsmax  < NPSMAX)) {
         /* No, free it. */
         wcsfree(wcs);
      }
d180 16
d197 16
a212 9
      if (alloc || wcs->crpix == 0x0) {
         if (wcs->m_crpix) {
            /* In case the caller fiddled with it. */
            wcs->crpix = wcs->m_crpix;

         } else {
            if (!(wcs->crpix = calloc(naxis, sizeof(double)))) {
               return 2;
            }
d214 16
a229 5
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_crpix = wcs->crpix;
         }
      }
d231 16
a246 10
      if (alloc || wcs->pc == 0x0) {
         if (wcs->m_pc) {
            /* In case the caller fiddled with it. */
            wcs->pc = wcs->m_pc;

         } else {
            if (!(wcs->pc = calloc(naxis*naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }
d248 16
a263 5
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_pc    = wcs->pc;
         }
      }
d265 22
a286 10
      if (alloc || wcs->cdelt == 0x0) {
         if (wcs->m_cdelt) {
            /* In case the caller fiddled with it. */
            wcs->cdelt = wcs->m_cdelt;

         } else {
            if (!(wcs->cdelt = calloc(naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }
d288 22
a309 5
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_cdelt = wcs->cdelt;
         }
      }
d311 16
a326 10
      if (alloc || wcs->crval == 0x0) {
         if (wcs->m_crval) {
            /* In case the caller fiddled with it. */
            wcs->crval = wcs->m_crval;

         } else {
            if (!(wcs->crval = calloc(naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }
d328 16
a343 5
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_crval = wcs->crval;
         }
      }
d345 16
a360 10
      if (alloc || wcs->cunit == 0x0) {
         if (wcs->m_cunit) {
            /* In case the caller fiddled with it. */
            wcs->cunit = wcs->m_cunit;

         } else {
            if (!(wcs->cunit = calloc(naxis, sizeof(char [72])))) {
               wcsfree(wcs);
               return 2;
            }
d362 16
a377 5
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_cunit = wcs->cunit;
         }
      }
d379 16
a394 10
      if (alloc || wcs->ctype == 0x0) {
         if (wcs->m_ctype) {
            /* In case the caller fiddled with it. */
            wcs->ctype = wcs->m_ctype;

         } else {
            if (!(wcs->ctype = calloc(naxis, sizeof(char [72])))) {
               wcsfree(wcs);
               return 2;
            }
d396 114
a509 147
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_ctype = wcs->ctype;
         }
      }

      if (alloc || wcs->pv == 0x0) {
         if (wcs->m_pv) {
            /* In case the caller fiddled with it. */
            wcs->pv = wcs->m_pv;

         } else {
            if (NPVMAX) {
               if (!(wcs->pv = calloc(NPVMAX, sizeof(struct pvcard)))) {
                  wcsfree(wcs);
                  return 2;
               }
            } else {
               wcs->pv = (struct pvcard *)0;
            }

            wcs->npvmax  = NPVMAX;

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_pv    = wcs->pv;
         }
      }

      if (alloc || wcs->ps == 0x0) {
         if (wcs->m_ps) {
            /* In case the caller fiddled with it. */
            wcs->ps = wcs->m_ps;

         } else {
            if (NPSMAX) {
              if (!(wcs->ps = calloc(NPSMAX, sizeof(struct pscard)))) {
                 wcsfree(wcs);
                 return 2;
              }
            } else {
              wcs->ps = (struct pscard *)0;
            }

            wcs->npsmax  = NPSMAX;

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_ps    = wcs->ps;
         }
      }

      if (alloc || wcs->cd == 0x0) {
         if (wcs->m_cd) {
            /* In case the caller fiddled with it. */
            wcs->cd = wcs->m_cd;

         } else {
            if (!(wcs->cd = calloc(naxis*naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_cd    = wcs->cd;
         }
      }

      if (alloc || wcs->crota == 0x0) {
         if (wcs->m_crota) {
            /* In case the caller fiddled with it. */
            wcs->crota = wcs->m_crota;

         } else {
            if (!(wcs->crota = calloc(naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_crota = wcs->crota;
         }
      }

      if (alloc || wcs->colax == 0x0) {
         if (wcs->m_colax) {
            /* In case the caller fiddled with it. */
            wcs->colax = wcs->m_colax;

         } else {
            if (!(wcs->colax = calloc(naxis, sizeof(int)))) {
               wcsfree(wcs);
               return 2;
            }

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_colax = wcs->colax;
         }
      }

      if (alloc || wcs->cname == 0x0) {
         if (wcs->m_cname) {
            /* In case the caller fiddled with it. */
            wcs->cname = wcs->m_cname;

         } else {
            if (!(wcs->cname = calloc(naxis, sizeof(char [72])))) {
               wcsfree(wcs);
               return 2;
            }

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_cname = wcs->cname;
         }
      }

      if (alloc || wcs->crder == 0x0) {
         if (wcs->m_crder) {
            /* In case the caller fiddled with it. */
            wcs->crder = wcs->m_crder;

         } else {
            if (!(wcs->crder = calloc(naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_crder = wcs->crder;
         }
      }

      if (alloc || wcs->csyer == 0x0) {
         if (wcs->m_csyer) {
            /* In case the caller fiddled with it. */
            wcs->csyer = wcs->m_csyer;

         } else {
            if (!(wcs->csyer = calloc(naxis, sizeof(double)))) {
               wcsfree(wcs);
               return 2;
            }
d511 2
a512 50
            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_csyer = wcs->csyer;
         }
      }
   }


   wcs->flag  = 0;
   wcs->naxis = naxis;


   /* Set defaults for the linear transformation. */
   wcs->lin.crpix  = wcs->crpix;
   wcs->lin.pc     = wcs->pc;
   wcs->lin.cdelt  = wcs->cdelt;
   wcs->lin.m_flag = 0;
   if ((status = linini(0, naxis, &(wcs->lin)))) {
      return status;
   }


   /* CRVALia defaults to 0.0. */
   for (i = 0; i < naxis; i++) {
      wcs->crval[i] = 0.0;
   }


   /* CUNITia and CTYPEia are blank by default. */
   for (i = 0; i < naxis; i++) {
      memset(wcs->cunit[i], 0, 72);
      memset(wcs->ctype[i], 0, 72);
   }


   /* Set defaults for the celestial transformation parameters. */
   wcs->lonpole = UNDEFINED;
   wcs->latpole = +90.0;

   /* Set defaults for the spectral transformation parameters. */
   wcs->restfrq =  0.0;
   wcs->restwav =  0.0;

   /* Default parameter values. */
   wcs->npv = 0;
   for (k = 0; k < wcs->npvmax; k++) {
     wcs->pv[k].i = 0;
     wcs->pv[k].m = 0;
     wcs->pv[k].value = 0.0;
   }
d514 1
a514 62
   wcs->nps = 0;
   for (k = 0; k < wcs->npsmax; k++) {
     wcs->ps[k].i = 0;
     wcs->ps[k].m = 0;
     memset(wcs->ps[k].value, 0, 72);
   }

   /* Defaults for alternate linear transformations. */
   wcs->altlin = 0;
   cd = wcs->cd;
   for (i = 0; i < naxis; i++) {
      for (j = 0; j < naxis; j++) {
         *(cd++) = 0.0;
      }
   }
   for (i = 0; i < naxis; i++) {
      wcs->crota[i] = 0.0;
   }

   /* Defaults for auxiliary coordinate system information. */
   memset(wcs->alt, 0, 4);
   wcs->alt[0] = ' ';
   wcs->colnum = 0;
   memset(wcs->wcsname, 0, 72);
   for (i = 0; i < naxis; i++) {
      wcs->colax[i] = 0;
      memset(wcs->cname[i], 0, 72);
      wcs->crder[i] = UNDEFINED;
      wcs->csyer[i] = UNDEFINED;
   }
   memset(wcs->radesys, 0, 72);
   wcs->equinox    = UNDEFINED;
   memset(wcs->specsys, 0, 72);
   memset(wcs->ssysobs, 0, 72);
   wcs->velosys    = UNDEFINED;
   memset(wcs->ssyssrc, 0, 72);
   wcs->zsource    = UNDEFINED;
   wcs->obsgeo[0]  = UNDEFINED;
   wcs->obsgeo[1]  = UNDEFINED;
   wcs->obsgeo[2]  = UNDEFINED;
   memset(wcs->dateobs, 0, 72);
   memset(wcs->dateavg, 0, 72);
   wcs->mjdobs     = UNDEFINED;
   wcs->mjdavg     = UNDEFINED;

   wcs->ntab = 0;
   wcs->tab  = 0x0;
   wcs->nwtb = 0;
   wcs->wtb  = 0x0;

   /* Reset derived values. */
   strcpy(wcs->lngtyp, "    ");
   strcpy(wcs->lattyp, "    ");
   wcs->lng  = -1;
   wcs->lat  = -1;
   wcs->spec = -1;
   wcs->cubeface = -1;

   celini(&(wcs->cel));
   spcini(&(wcs->spc));

   return 0;
d520 5
a524 5
   int alloc,
   const struct wcsprm *wcssrc,
   int *nsub,
   int axes[],
   struct wcsprm *wcsdst)
d527 28
a554 10
   char *c, ctypei[16];
   int  axis, cubeface, dealloc, dummy, i, itab, j, k, latitude, longitude,
        m, *map = 0x0, msub, naxis, npv, nps, other, spectral, status, stokes;
   const double *srcp;
   double *dstp;
   struct tabprm *tabp;

   if (wcssrc == 0x0) return 1;

   if ((naxis = wcssrc->naxis) <= 0) {
d556 1
a556 1
   }
d558 26
a583 16
   if (!(map = calloc(naxis, sizeof(int)))) {
      return 2;
   }

   if (nsub == 0x0) {
      nsub = &dummy;
      *nsub = naxis;
   } else if (*nsub == 0) {
      *nsub = naxis;
   }

   if ((dealloc = (axes == 0x0))) {
      /* Construct an index array. */
      if (!(axes = calloc(naxis, sizeof(int)))) {
         free(map);
         return 2;
d587 2
a588 3
         axes[i] = i+1;
      }
   }
d590 74
a663 107

   msub = 0;
   for (j = 0; j < *nsub; j++) {
      axis = axes[j];

      if (abs(axis) > 0x1000) {
         /* Subimage extraction by type. */
         k = abs(axis) & 0xFF;

         longitude = k & WCSSUB_LONGITUDE;
         latitude  = k & WCSSUB_LATITUDE;
         cubeface  = k & WCSSUB_CUBEFACE;
         spectral  = k & WCSSUB_SPECTRAL;
         stokes    = k & WCSSUB_STOKES;

         if ((other = (axis < 0))) {
            longitude = !longitude;
            latitude  = !latitude;
            cubeface  = !cubeface;
            spectral  = !spectral;
            stokes    = !stokes;
         }

         for (i = 0; i < naxis; i++) {
            strncpy (ctypei, (char *)(wcssrc->ctype + i), 8);
            ctypei[8] = '\0';

            /* Find the last non-blank character. */
            c = ctypei + 8;
            while (c-- > ctypei) {
               if (*c == ' ') *c = '\0';
               if (*c != '\0') break;
            }

            if (
               strcmp(ctypei,   "RA")  == 0 ||
               strcmp(ctypei+1, "LON") == 0 ||
               strcmp(ctypei+2, "LN")  == 0 ||
               strncmp(ctypei,   "RA---", 5) == 0 ||
               strncmp(ctypei+1, "LON-", 4) == 0 ||
               strncmp(ctypei+2, "LN-", 3) == 0) {
               if (!longitude) {
                  continue;
               }

            } else if (
               strcmp(ctypei,   "DEC") == 0 ||
               strcmp(ctypei+1, "LAT") == 0 ||
               strcmp(ctypei+2, "LT")  == 0 ||
               strncmp(ctypei,   "DEC--", 5) == 0 ||
               strncmp(ctypei+1, "LAT-", 4) == 0 ||
               strncmp(ctypei+2, "LT-", 3) == 0) {
               if (!latitude) {
                  continue;
               }

            } else if (strcmp(ctypei, "CUBEFACE") == 0) {
               if (!cubeface) {
                  continue;
               }

            } else if ((
               strncmp(ctypei, "FREQ", 4) == 0 ||
               strncmp(ctypei, "ENER", 4) == 0 ||
               strncmp(ctypei, "WAVN", 4) == 0 ||
               strncmp(ctypei, "VRAD", 4) == 0 ||
               strncmp(ctypei, "WAVE", 4) == 0 ||
               strncmp(ctypei, "VOPT", 4) == 0 ||
               strncmp(ctypei, "ZOPT", 4) == 0 ||
               strncmp(ctypei, "AWAV", 4) == 0 ||
               strncmp(ctypei, "VELO", 4) == 0 ||
               strncmp(ctypei, "BETA", 4) == 0) &&
               (ctypei[4] == '\0' || ctypei[4] == '-')) {
               if (!spectral) {
                  continue;
               }

            } else if (strcmp(ctypei, "STOKES") == 0) {
               if (!stokes) {
                  continue;
               }

            } else if (!other) {
               continue;
            }

            /* This axis is wanted, but has it already been added? */
            for (k = 0; k < msub; k++) {
               if (map[k] == i+1) {
                  break;
               }
            }
            if (k == msub) map[msub++] = i+1;
         }

      } else if (0 < axis && axis <= naxis) {
         /* Check that the requested axis has not already been added. */
         for (k = 0; k < msub; k++) {
            if (map[k] == axis) {
               break;
            }
         }
         if (k == msub) map[msub++] = axis;

      } else {
         status = 12;
         goto cleanup;
d665 1
a665 1
   }
d667 2
a668 2
   if ((*nsub = msub) == 0) {
      status = 0;
d670 2
a671 1
   }
d673 25
a697 20
   for (i = 0; i < *nsub; i++) {
      axes[i] = map[i];
   }


   /* Construct the inverse axis map. */
   for (i = 0; i < naxis; i++) {
      map[i] = 0;
   }

   for (i = 0; i < *nsub; i++) {
      map[axes[i]-1] = i+1;
   }

   /* Check that the subimage coordinate system is separable. */
   if (*nsub < naxis) {
      srcp = wcssrc->pc;
      for (i = 0; i < naxis; i++) {
         for (j = 0; j < naxis; j++) {
            if (*(srcp++) == 0.0 || j == i) continue;
d699 52
a750 44
            if ((map[i] == 0) != (map[j] == 0)) {
               status = 13;
               goto cleanup;
            }
         }
      }
   }


   /* Initialize the destination. */
   npv = NPVMAX;
   nps = NPSMAX;

   NPVMAX = 0;
   for (k = 0; k < wcssrc->npv; k++) {
      i = wcssrc->pv[k].i;
      if (i == 0 || (i > 0 && map[i-1])) {
         NPVMAX++;
      }
   }

   NPSMAX = 0;
   for (k = 0; k < wcssrc->nps; k++) {
      i = wcssrc->ps[k].i;
      if (i > 0 && map[i-1]) {
         NPSMAX++;
      }
   }

   status = wcsini(alloc, *nsub, wcsdst);

   NPVMAX = npv;
   NPSMAX = nps;

   if (status) {
      goto cleanup;
   }


   /* Linear transformation. */
   srcp = wcssrc->crpix;
   dstp = wcsdst->crpix;
   for (j = 0; j < *nsub; j++) {
      k = axes[j] - 1;
d752 2
a753 10
   }

   srcp = wcssrc->pc;
   dstp = wcsdst->pc;
   for (i = 0; i < *nsub; i++) {
      for (j = 0; j < *nsub; j++) {
         k = (axes[i]-1)*naxis + (axes[j]-1);
         *(dstp++) = *(srcp+k);
      }
   }
d755 60
a814 4
   srcp = wcssrc->cdelt;
   dstp = wcsdst->cdelt;
   for (i = 0; i < *nsub; i++) {
      k = axes[i] - 1;
d816 2
a817 1
   }
d819 57
a875 7
   /* Coordinate reference value. */
   srcp = wcssrc->crval;
   dstp = wcsdst->crval;
   for (i = 0; i < *nsub; i++) {
      k = axes[i] - 1;
      *(dstp++) = *(srcp+k);
   }
d877 3
a879 6
   /* Coordinate units and type. */
   for (i = 0; i < *nsub; i++) {
      k = axes[i] - 1;
      strncpy(wcsdst->cunit[i], wcssrc->cunit[k], 72);
      strncpy(wcsdst->ctype[i], wcssrc->ctype[k], 72);
   }
d881 2
a882 29
   /* Celestial and spectral transformation parameters. */
   wcsdst->lonpole = wcssrc->lonpole;
   wcsdst->latpole = wcssrc->latpole;
   wcsdst->restfrq = wcssrc->restfrq;
   wcsdst->restwav = wcssrc->restwav;

   /* Parameter values. */
   npv = 0;
   for (k = 0; k < wcssrc->npv; k++) {
      i = wcssrc->pv[k].i;
      if (i == 0 || (i > 0 && map[i-1])) {
         /* i == 0 is a special code for the latitude axis. */
         wcsdst->pv[npv] = wcssrc->pv[k];
         wcsdst->pv[npv].i = map[i-1];
         npv++;
      }
   }
   wcsdst->npv = npv;

   nps = 0;
   for (k = 0; k < wcssrc->nps; k++) {
      i = wcssrc->ps[k].i;
      if (i > 0 && map[i-1]) {
         wcsdst->ps[nps] = wcssrc->ps[k];
         wcsdst->ps[nps].i = map[i-1];
         nps++;
      }
   }
   wcsdst->nps = nps;
d884 9
a892 2
   /* Alternate linear transformations. */
   wcsdst->altlin = wcssrc->altlin;
d894 2
a895 69
   srcp = wcssrc->cd;
   dstp = wcsdst->cd;
   for (i = 0; i < *nsub; i++) {
      for (j = 0; j < *nsub; j++) {
         k = (axes[i]-1)*naxis + (axes[j]-1);
         *(dstp++) = *(srcp+k);
      }
   }

   srcp = wcssrc->crota;
   dstp = wcsdst->crota;
   for (i = 0; i < *nsub; i++) {
      k = axes[i] - 1;
      *(dstp++) = *(srcp+k);
   }

   /* Auxiliary coordinate system information. */
   strncpy(wcsdst->alt, wcssrc->alt, 4);
   wcsdst->colnum = wcssrc->colnum;

   strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);
   for (i = 0; i < *nsub; i++) {
      k = axes[i] - 1;
      wcsdst->colax[i] = wcssrc->colax[k];
      strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
      wcsdst->crder[i] = wcssrc->crder[k];
      wcsdst->csyer[i] = wcssrc->csyer[k];
   }

   strncpy(wcsdst->radesys, wcssrc->radesys, 72);
   wcsdst->equinox = wcssrc->equinox;

   strncpy(wcsdst->specsys, wcssrc->specsys, 72);
   strncpy(wcsdst->ssysobs, wcssrc->ssysobs, 72);
   wcsdst->velosys = wcssrc->velosys;
   strncpy(wcsdst->ssyssrc, wcssrc->ssyssrc, 72);
   wcsdst->zsource = wcssrc->zsource;

   wcsdst->obsgeo[0] = wcssrc->obsgeo[0];
   wcsdst->obsgeo[1] = wcssrc->obsgeo[1];
   wcsdst->obsgeo[2] = wcssrc->obsgeo[2];

   strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);
   strncpy(wcsdst->dateavg, wcssrc->dateavg, 72);
   wcsdst->mjdobs = wcssrc->mjdobs;
   wcsdst->mjdavg = wcssrc->mjdavg;


   /* Coordinate lookup tables; only copy what's needed. */
   wcsdst->ntab = 0;
   for (itab = 0; itab < wcssrc->ntab; itab++) {
      /* Is this table wanted? */
      for (m = 0; m < wcssrc->tab[itab].M; m++) {
         i = wcssrc->tab[itab].map[m];

         if (map[i-1]) {
            wcsdst->ntab++;
            break;
         }
      }
   }

   if (wcsdst->ntab) {
      /* Allocate memory for tabprm structs. */
      if (!(wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm)))) {
         wcsdst->ntab = 0;

         status = 2;
         goto cleanup;
d897 2
a898 19

      wcsdst->m_tab = wcsdst->tab;
   }

   tabp = wcsdst->tab;
   for (itab = 0; itab < wcssrc->ntab; itab++) {
      for (m = 0; m < wcssrc->tab[itab].M; m++) {
         i = wcssrc->tab[itab].map[m];

         if (map[i-1]) {
            if ((status = tabcpy(1, wcssrc->tab + itab, tabp))) {
               goto cleanup;
            }

            tabp++;
            break;
         }
      }
   }
d902 4
a905 4
   if (map) free(map);
   if (dealloc) {
     free(axes);
   }
d907 1
a907 1
   if (status && wcsdst->m_tab) free(wcsdst->m_tab);
d909 1
a909 1
   return status;
d917 1
a917 1
   int j;
d919 1
a919 1
   if (wcs == 0x0) return 1;
d921 2
a922 2
   if (wcs->flag == -1) {
      wcs->lin.flag = -1;
d924 75
a998 40
   } else {
      /* Free memory allocated by wcsini(). */
      if (wcs->m_flag == WCSSET) {
         if (wcs->crpix == wcs->m_crpix) wcs->crpix = 0x0;
         if (wcs->pc    == wcs->m_pc)    wcs->pc    = 0x0;
         if (wcs->cdelt == wcs->m_cdelt) wcs->cdelt = 0x0;
         if (wcs->crval == wcs->m_crval) wcs->crval = 0x0;
         if (wcs->cunit == wcs->m_cunit) wcs->cunit = 0x0;
         if (wcs->ctype == wcs->m_ctype) wcs->ctype = 0x0;
         if (wcs->pv    == wcs->m_pv)    wcs->pv    = 0x0;
         if (wcs->ps    == wcs->m_ps)    wcs->ps    = 0x0;
         if (wcs->cd    == wcs->m_cd)    wcs->cd    = 0x0;
         if (wcs->crota == wcs->m_crota) wcs->crota = 0x0;
         if (wcs->colax == wcs->m_colax) wcs->colax = 0x0;
         if (wcs->cname == wcs->m_cname) wcs->cname = 0x0;
         if (wcs->crder == wcs->m_crder) wcs->crder = 0x0;
         if (wcs->csyer == wcs->m_csyer) wcs->csyer = 0x0;
         if (wcs->tab   == wcs->m_tab)   wcs->tab   = 0x0;
         if (wcs->wtb   == wcs->m_wtb)   wcs->wtb   = 0x0;

         if (wcs->m_crpix)  free(wcs->m_crpix);
         if (wcs->m_pc)     free(wcs->m_pc);
         if (wcs->m_cdelt)  free(wcs->m_cdelt);
         if (wcs->m_crval)  free(wcs->m_crval);
         if (wcs->m_cunit)  free(wcs->m_cunit);
         if (wcs->m_ctype)  free(wcs->m_ctype);
         if (wcs->m_pv)     free(wcs->m_pv);
         if (wcs->m_ps)     free(wcs->m_ps);
         if (wcs->m_cd)     free(wcs->m_cd);
         if (wcs->m_crota)  free(wcs->m_crota);
         if (wcs->m_colax)  free(wcs->m_colax);
         if (wcs->m_cname)  free(wcs->m_cname);
         if (wcs->m_crder)  free(wcs->m_crder);
         if (wcs->m_csyer)  free(wcs->m_csyer);

          /* Free memory allocated by wcstab(). */
         if (wcs->m_tab) {
            for (j = 0; j < wcs->ntab; j++) {
               tabfree(wcs->m_tab + j);
            }
d1000 1
a1000 12
            free(wcs->m_tab);
         }
         if (wcs->m_wtb) free(wcs->m_wtb);
      }

      /* Free memory allocated by wcsset(). */
      if (wcs->types) free(wcs->types);

      if (wcs->lin.crpix == wcs->m_crpix) wcs->lin.crpix = 0x0;
      if (wcs->lin.pc    == wcs->m_pc)    wcs->lin.pc    = 0x0;
      if (wcs->lin.cdelt == wcs->m_cdelt) wcs->lin.cdelt = 0x0;
   }
d1002 1
a1002 21
   wcs->m_flag   = 0;
   wcs->m_naxis  = 0x0;
   wcs->m_crpix  = 0x0;
   wcs->m_pc     = 0x0;
   wcs->m_cdelt  = 0x0;
   wcs->m_crval  = 0x0;
   wcs->m_cunit  = 0x0;
   wcs->m_ctype  = 0x0;
   wcs->m_pv     = 0x0;
   wcs->m_ps     = 0x0;
   wcs->m_cd     = 0x0;
   wcs->m_crota  = 0x0;
   wcs->m_colax  = 0x0;
   wcs->m_cname  = 0x0;
   wcs->m_crder  = 0x0;
   wcs->m_csyer  = 0x0;

   wcs->ntab  = 0;
   wcs->m_tab = 0x0;
   wcs->nwtb  = 0;
   wcs->m_wtb = 0x0;
d1004 1
a1004 5
   wcs->types = 0x0;

   wcs->flag = 0;

   return linfree(&(wcs->lin));
d1012 2
a1013 9
   int i, j, k;
   struct wtbarr *wtbp;

   if (wcs == 0x0) return 1;

   if (wcs->flag != WCSSET) {
      printf("The wcsprm struct is UNINITIALIZED.\n");
      return 0;
   }
d1015 1
a1015 8
   printf("       flag: %d\n", wcs->flag);
   printf("      naxis: %d\n", wcs->naxis);
   printf("      crpix: %p\n", (void *)wcs->crpix);
   printf("            ");
   for (i = 0; i < wcs->naxis; i++) {
      printf("  %- 11.5g", wcs->crpix[i]);
   }
   printf("\n");
d1017 86
a1102 5
   /* Linear transformation. */
   k = 0;
   printf("         pc: %p\n", (void *)wcs->pc);
   for (i = 0; i < wcs->naxis; i++) {
      printf("    pc[%d][]:", i);
d1104 1
a1104 1
         printf("  %- 11.5g", wcs->pc[k++]);
d1107 2
a1108 1
   }
d1110 35
a1144 65
   /* Coordinate increment at reference point. */
   printf("      cdelt: %p\n", (void *)wcs->cdelt);
   printf("            ");
   for (i = 0; i < wcs->naxis; i++) {
      printf("  %- 11.5g", wcs->cdelt[i]);
   }
   printf("\n");

   /* Coordinate value at reference point. */
   printf("      crval: %p\n", (void *)wcs->crval);
   printf("            ");
   for (i = 0; i < wcs->naxis; i++) {
      printf("  %- 11.5g", wcs->crval[i]);
   }
   printf("\n");

   /* Coordinate units and type. */
   printf("      cunit: %p\n", (void *)wcs->cunit);
   for (i = 0; i < wcs->naxis; i++) {
      printf("             \"%s\"\n", wcs->cunit[i]);
   }

   printf("      ctype: %p\n", (void *)wcs->ctype);
   for (i = 0; i < wcs->naxis; i++) {
      printf("             \"%s\"\n", wcs->ctype[i]);
   }

   /* Celestial and spectral transformation parameters. */
   if (undefined(wcs->lonpole)) {
      printf("    lonpole: UNDEFINED\n");
   } else {
      printf("    lonpole: %9f\n", wcs->lonpole);
   }
   printf("    latpole: %9f\n", wcs->latpole);
   printf("    restfrq: %f\n", wcs->restfrq);
   printf("    restwav: %f\n", wcs->restwav);

   /* Parameter values. */
   printf("        npv: %d\n", wcs->npv);
   printf("     npvmax: %d\n", wcs->npvmax);
   printf("         pv: %p\n", (void *)wcs->pv);
   for (i = 0; i < wcs->npv; i++) {
      printf("             %3d%4d  %- 11.5g\n", (wcs->pv[i]).i,
         (wcs->pv[i]).m, (wcs->pv[i]).value);
   }
   printf("        nps: %d\n", wcs->nps);
   printf("     npsmax: %d\n", wcs->npsmax);
   printf("         ps: %p\n", (void *)wcs->ps);
   for (i = 0; i < wcs->nps; i++) {
      printf("             %3d%4d  %s\n", (wcs->ps[i]).i,
         (wcs->ps[i]).m, (wcs->ps[i]).value);
   }

   /* Alternate linear transformations. */
   printf("     altlin: %d\n", wcs->altlin);

   k = 0;
   printf("         cd: %p\n", (void *)wcs->cd);
   if (wcs->cd) {
      for (i = 0; i < wcs->naxis; i++) {
         printf("    cd[%d][]:", i);
         for (j = 0; j < wcs->naxis; j++) {
            printf("  %- 11.5g", wcs->cd[k++]);
         }
         printf("\n");
d1146 2
a1147 1
   }
d1149 8
a1156 5
   printf("      crota: %p\n", (void *)wcs->crota);
   if (wcs->crota) {
      printf("            ");
      for (i = 0; i < wcs->naxis; i++) {
         printf("  %- 11.5g", wcs->crota[i]);
d1158 12
a1169 12
      printf("\n");
   }

   /* Auxiliary coordinate system information. */
   printf("        alt: '%c'\n", wcs->alt[0]);
   printf("     colnum: %d\n", wcs->colnum);

   printf("      colax: %p\n", (void *)wcs->colax);
   if (wcs->colax) {
      printf("           ");
      for (i = 0; i < wcs->naxis; i++) {
         printf("  %5d", wcs->colax[i]);
d1171 163
d1335 15
a1349 18
   }

   if (wcs->wcsname[0] == '\0') {
      printf("    wcsname: UNDEFINED\n");
   } else {
      printf("    wcsname: \"%s\"\n", wcs->wcsname);
   }

   printf("      cname: %p\n", (void *)wcs->cname);
   if (wcs->cname) {
      for (i = 0; i < wcs->naxis; i++) {
         if (wcs->cname[i][0] == '\0') {
            printf("             UNDEFINED\n");
         } else {
            printf("             \"%s\"\n", wcs->cname[i]);
         }
      }
   }
d1351 2
a1352 10
   printf("      crder: %p\n", (void *)wcs->crder);
   if (wcs->crder) {
      printf("           ");
      for (i = 0; i < wcs->naxis; i++) {
         if (undefined(wcs->crder[i])) {
            printf("  UNDEFINED   ");
         } else {
            printf("  %- 11.5g", wcs->crder[i]);
         }
      }
d1354 19
a1372 1
   }
d1374 2
a1375 12
   printf("      csyer: %p\n", (void *)wcs->csyer);
   if (wcs->csyer) {
      printf("           ");
      for (i = 0; i < wcs->naxis; i++) {
         if (undefined(wcs->csyer[i])) {
            printf("  UNDEFINED   ");
         } else {
            printf("  %- 11.5g", wcs->csyer[i]);
         }
      }
      printf("\n");
   }
d1377 1
a1377 5
   if (wcs->radesys[0] == '\0') {
      printf("    radesys: UNDEFINED\n");
   } else {
      printf("    radesys: \"%s\"\n", wcs->radesys);
   }
d1379 1
a1379 5
   if (undefined(wcs->equinox)) {
      printf("    equinox: UNDEFINED\n");
   } else {
      printf("    equinox: %9f\n", wcs->equinox);
   }
d1381 223
a1603 5
   if (wcs->specsys[0] == '\0') {
      printf("    specsys: UNDEFINED\n");
   } else {
      printf("    specsys: \"%s\"\n", wcs->specsys);
   }
d1605 1
a1605 5
   if (wcs->ssysobs[0] == '\0') {
      printf("    ssysobs: UNDEFINED\n");
   } else {
      printf("    ssysobs: \"%s\"\n", wcs->ssysobs);
   }
d1607 2
a1608 5
   if (undefined(wcs->velosys)) {
      printf("    velosys: UNDEFINED\n");
   } else {
      printf("    velosys: %9f\n", wcs->velosys);
   }
a1609 5
   if (wcs->ssyssrc[0] == '\0') {
      printf("    ssyssrc: UNDEFINED\n");
   } else {
      printf("    ssyssrc: \"%s\"\n", wcs->ssyssrc);
   }
d1611 1
a1611 5
   if (undefined(wcs->zsource)) {
      printf("    zsource: UNDEFINED\n");
   } else {
      printf("    zsource: %9f\n", wcs->zsource);
   }
d1613 3
a1615 9
   printf("     obsgeo: ");
   for (i = 0; i < 3; i++) {
      if (undefined(wcs->obsgeo[i])) {
         printf("UNDEFINED     ");
      } else {
         printf("%- 11.5g  ", wcs->obsgeo[i]);
      }
   }
   printf("\n");
d1617 2
a1618 5
   if (wcs->dateobs[0] == '\0') {
      printf("    dateobs: UNDEFINED\n");
   } else {
      printf("    dateobs: \"%s\"\n", wcs->dateobs);
   }
a1619 5
   if (wcs->dateavg[0] == '\0') {
      printf("    dateavg: UNDEFINED\n");
   } else {
      printf("    dateavg: \"%s\"\n", wcs->dateavg);
   }
d1621 1
a1621 5
   if (undefined(wcs->mjdobs)) {
      printf("     mjdobs: UNDEFINED\n");
   } else {
      printf("     mjdobs: %9f\n", wcs->mjdobs);
   }
d1623 179
a1801 5
   if (undefined(wcs->mjdavg)) {
      printf("     mjdavg: UNDEFINED\n");
   } else {
      printf("     mjdavg: %9f\n", wcs->mjdavg);
   }
d1803 35
a1837 15
   printf("       ntab: %d\n", wcs->ntab);
   printf("        tab: %p", (void *)wcs->tab);
   if (wcs->tab != 0x0) printf("  (see below)");
   printf("\n");
   printf("       nwtb: %d\n", wcs->nwtb);
   printf("        wtb: %p", (void *)wcs->wtb);
   if (wcs->wtb != 0x0) printf("  (see below)");
   printf("\n");

   /* Derived values. */
   printf("      types: %p\n           ", (void *)wcs->types);
   for (i = 0; i < wcs->naxis; i++) {
      printf("%5d", wcs->types[i]);
   }
   printf("\n");
d1839 3
a1841 81
   printf("     lngtyp: \"%s\"\n", wcs->lngtyp);
   printf("     lattyp: \"%s\"\n", wcs->lattyp);
   printf("        lng: %d\n", wcs->lng);
   printf("        lat: %d\n", wcs->lat);
   printf("       spec: %d\n", wcs->spec);
   printf("   cubeface: %d\n", wcs->cubeface);

   printf("        lin: (see below)\n");
   printf("        cel: (see below)\n");
   printf("        spc: (see below)\n");

   /* Memory management. */
   printf("     m_flag: %d\n", wcs->m_flag);
   printf("    m_naxis: %d\n", wcs->m_naxis);
   printf("    m_crpix: %p", (void *)wcs->m_crpix);
   if (wcs->m_crpix == wcs->crpix) printf("  (= crpix)");
   printf("\n");
   printf("       m_pc: %p", (void *)wcs->m_pc);
   if (wcs->m_pc == wcs->pc) printf("  (= pc)");
   printf("\n");
   printf("    m_cdelt: %p", (void *)wcs->m_cdelt);
   if (wcs->m_cdelt == wcs->cdelt) printf("  (= cdelt)");
   printf("\n");
   printf("    m_crval: %p", (void *)wcs->m_crval);
   if (wcs->m_crval == wcs->crval) printf("  (= crval)");
   printf("\n");
   printf("    m_cunit: %p", (void *)wcs->m_cunit);
   if (wcs->m_cunit == wcs->cunit) printf("  (= cunit)");
   printf("\n");
   printf("    m_ctype: %p", (void *)wcs->m_ctype);
   if (wcs->m_ctype == wcs->ctype) printf("  (= ctype)");
   printf("\n");
   printf("       m_pv: %p", (void *)wcs->m_pv);
   if (wcs->m_pv == wcs->pv) printf("  (= pv)");
   printf("\n");
   printf("       m_ps: %p", (void *)wcs->m_ps);
   if (wcs->m_ps == wcs->ps) printf("  (= ps)");
   printf("\n");
   printf("       m_cd: %p", (void *)wcs->m_cd);
   if (wcs->m_cd == wcs->cd) printf("  (= cd)");
   printf("\n");
   printf("    m_crota: %p", (void *)wcs->m_crota);
   if (wcs->m_crota == wcs->crota) printf("  (= crota)");
   printf("\n");
   printf("\n");
   printf("    m_colax: %p", (void *)wcs->m_colax);
   if (wcs->m_colax == wcs->colax) printf("  (= colax)");
   printf("\n");
   printf("    m_cname: %p", (void *)wcs->m_cname);
   if (wcs->m_cname == wcs->cname) printf("  (= cname)");
   printf("\n");
   printf("    m_crder: %p", (void *)wcs->m_crder);
   if (wcs->m_crder == wcs->crder) printf("  (= crder)");
   printf("\n");
   printf("    m_csyer: %p", (void *)wcs->m_csyer);
   if (wcs->m_csyer == wcs->csyer) printf("  (= csyer)");
   printf("\n");
   printf("      m_tab: %p", (void *)wcs->m_tab);
   if (wcs->m_tab == wcs->tab) printf("  (= tab)");
   printf("\n");
   printf("      m_wtb: %p", (void *)wcs->m_wtb);
   if (wcs->m_wtb == wcs->wtb) printf("  (= wtb)");
   printf("\n");

   /* Tabular transformation parameters. */
   if ((wtbp = wcs->wtb)) {
      for (j = 0; j < wcs->nwtb; j++, wtbp++) {
         printf("\n");
         printf("wtb[%d].*\n", j);
         printf("          i: %d\n", wtbp->i);
         printf("          m: %d\n", wtbp->m);
         printf("       kind: %c\n", wtbp->kind);
         printf("     extnam: %s\n", wtbp->extnam);
         printf("     extver: %d\n", wtbp->extver);
         printf("     extlev: %d\n", wtbp->extlev);
         printf("      ttype: %s\n", wtbp->ttype);
         printf("        row: %ld\n", wtbp->row);
         printf("       ndim: %d\n", wtbp->ndim);
         printf("     dimlen: %p\n", (void *)wtbp->dimlen);
         printf("     arrayp: %p -> %p\n", (void *)wtbp->arrayp,
                                           (void *)(*(wtbp->arrayp)));
d1843 3
a1845 9
   }

   if (wcs->tab) {
      for (j = 0; j < wcs->ntab; j++) {
         printf("\n");
         printf("tab[%d].*\n", j);
         tabprt(wcs->tab + j);
      }
   }
d1847 1
a1847 16
   /* Linear transformation parameters. */
   printf("\n");
   printf("   lin.*\n");
   linprt(&(wcs->lin));

   /* Celestial transformation parameters. */
   printf("\n");
   printf("   cel.*\n");
   celprt(&(wcs->cel));

   /* Spectral transformation parameters. */
   printf("\n");
   printf("   spc.*\n");
   spcprt(&(wcs->spc));

   return 0;
a1849 1
/*--------------------------------------------------------------------------*/
d1851 1
a1851 1
int wcsset(struct wcsprm *wcs)
d1854 53
a1906 7
   char scode[4], stype[5];
   int i, j, k, m, naxis, status;
   double lambda, rho;
   double *cd, *pc;
   struct celprm *wcscel = &(wcs->cel);
   struct prjprm *wcsprj = &(wcscel->prj);
   struct spcprm *wcsspc = &(wcs->spc);
d1908 2
d1911 1
a1911 5
   /* Determine axis types from CTYPEia. */
   if (wcs == 0x0) return 1;
   if ((status = wcs_types(wcs))) {
      return status;
   }
d1913 10
a1922 4
   /* Convert to canonical units. */
   if ((status = wcs_units(wcs))) {
      return status;
   }
d1924 67
d1992 2
a1993 25
   /* Non-linear celestial axes present? */
   if (wcs->lng >= 0 && wcs->types[wcs->lng] == 2200) {
      celini(wcscel);

      /* CRVALia, LONPOLEa, and LATPOLEa keyvalues. */
      wcscel->ref[0] = wcs->crval[wcs->lng];
      wcscel->ref[1] = wcs->crval[wcs->lat];
      wcscel->ref[2] = wcs->lonpole;
      wcscel->ref[3] = wcs->latpole;

      /* PVi_ma keyvalues. */
      for (k = 0; k < wcs->npv; k++) {
         i = wcs->pv[k].i - 1;
         m = wcs->pv[k].m;

         if (i == 0) {
            /* From a PROJPn keyword. */
            i = wcs->lat;
         }

         if (i == wcs->lat) {
            /* PVi_ma associated with latitude axis. */
            if (m < 30) {
               wcsprj->pv[m] = wcs->pv[k].value;
            }
d1995 1
a1995 3
         } else if (i == wcs->lng) {
            /* PVi_ma associated with longitude axis. */
            switch (m) {
d1997 2
a1998 2
               wcscel->offset = (wcs->pv[k].value != 0.0);
               break;
d2000 1
a2000 2
               wcscel->phi0   = wcs->pv[k].value;
               break;
d2002 2
a2003 2
               wcscel->theta0 = wcs->pv[k].value;
               break;
d2005 2
a2006 3
               /* If present, overrides LONPOLEa. */
               wcscel->ref[2] = wcs->pv[k].value;
               break;
d2008 5
a2012 3
               /* If present, overrides LATPOLEa. */
               wcscel->ref[3] = wcs->pv[k].value;
               break;
d2014 2
a2015 2
               return 6;
               break;
d2017 4
a2020 1
         }
d2023 32
a2054 3
      /* Do simple alias translations. */
      if (strncmp(wcs->ctype[wcs->lng]+5, "GLS", 3) == 0) {
         strcpy(wcsprj->code, "SFL");
d2056 3
a2058 12
      } else if (strcmp(wcs->ctype[wcs->lng]+5, "NCP") == 0) {
         /* Convert NCP to SIN. */
         if (wcscel->ref[1] == 0.0) {
            return 5;
         }

         strcpy(wcsprj->code, "SIN");
         wcsprj->pv[1] = 0.0;
         wcsprj->pv[2] = cosd(wcscel->ref[1])/sind(wcscel->ref[1]);

      } else {
         strcpy(wcsprj->code, wcs->ctype[wcs->lng]+5);
d2061 5
a2065 4
      /* Initialize the celestial transformation routines. */
      wcsprj->r0 = 0.0;
      if ((status = celset(wcscel))) {
         return status + 3;
d2068 5
a2072 3
      /* Update LONPOLE, LATPOLE, and PVi_ma keyvalues. */
      wcs->lonpole = wcscel->ref[2];
      wcs->latpole = wcscel->ref[3];
d2074 5
a2078 3
      for (k = 0; k < wcs->npv; k++) {
         i = wcs->pv[k].i - 1;
         m = wcs->pv[k].m;
d2080 7
a2086 16
         if (i == wcs->lng) {
            switch (m) {
            case 1:
               wcs->pv[k].value = wcscel->phi0;
               break;
            case 2:
               wcs->pv[k].value = wcscel->theta0;
               break;
            case 3:
               wcs->pv[k].value = wcscel->ref[2];
               break;
            case 4:
               wcs->pv[k].value = wcscel->ref[3];
               break;
            }
         }
a2087 1
   }
d2089 4
a2092 24

   /* Non-linear spectral axis present? */
   if (wcs->spec >= 0 && wcs->types[wcs->spec] == 3300) {
      spcini(wcsspc);
      spctyp(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0, 0x0, 0x0);
      strcpy(wcsspc->type, stype);
      strcpy(wcsspc->code, scode);

      /* CRVALia, RESTFRQa, and RESTWAVa keyvalues. */
      wcsspc->crval = wcs->crval[wcs->spec];
      wcsspc->restfrq = wcs->restfrq;
      wcsspc->restwav = wcs->restwav;

      /* PVi_ma keyvalues. */
      for (k = 0; k < wcs->npv; k++) {
         i = wcs->pv[k].i - 1;
         m = wcs->pv[k].m;

         if (i == wcs->spec) {
            /* PVi_ma associated with grism axis. */
            if (m < 7) {
               wcsspc->pv[m] = wcs->pv[k].value;
            }
         }
d2095 2
a2096 3
      /* Initialize the spectral transformation routines. */
      if ((status = spcset(wcsspc))) {
         return status + 3;
d2098 2
a2099 1
   }
d2102 3
a2104 6
   /* Tabular axes present? */
   for (j = 0; j < wcs->ntab; j++) {
      if ((status = tabset(wcs->tab + j))) {
         return status + 3;
      }
   }
d2106 2
d2109 3
a2111 29
   /* Initialize the linear transformation. */
   naxis = wcs->naxis;
   wcs->altlin &= 7;
   if (wcs->altlin > 1 && !(wcs->altlin & 1)) {
      pc = wcs->pc;

      if (wcs->altlin & 2) {
         /* Copy CDi_ja to PCi_ja and reset CDELTia. */
         cd = wcs->cd;
         for (i = 0; i < naxis; i++) {
            for (j = 0; j < naxis; j++) {
               *(pc++) = *(cd++);
            }
            wcs->cdelt[i] = 1.0;
         }

      } else if (wcs->altlin & 4) {
         /* Construct PCi_ja from CROTAia. */
         if ((i = wcs->lng) >= 0 && (j = wcs->lat) >= 0) {
            rho = wcs->crota[j];

            if (wcs->cdelt[i] == 0.0) return 3;
            lambda = wcs->cdelt[j]/wcs->cdelt[i];

            *(pc + i*naxis + i) = *(pc + j*naxis + j) = cosd(rho);
            *(pc + i*naxis + j) = *(pc + j*naxis + i) = sind(rho);
            *(pc + i*naxis + j) *= -lambda;
            *(pc + j*naxis + i) /=  lambda;
         }
d2113 1
a2113 1
   }
d2115 5
a2119 6
   wcs->lin.crpix  = wcs->crpix;
   wcs->lin.pc     = wcs->pc;
   wcs->lin.cdelt  = wcs->cdelt;
   if ((status = linset(&(wcs->lin)))) {
      return status;
   }
d2122 5
a2126 12
   /* Strip off trailing blanks and null-fill auxiliary string members. */
   wcsutil_null_fill(4, wcs->alt);
   wcsutil_null_fill(72, wcs->wcsname);
   for (i = 0; i < naxis; i++) {
      wcsutil_null_fill(72, wcs->cname[i]);
   }
   wcsutil_null_fill(72, wcs->radesys);
   wcsutil_null_fill(72, wcs->specsys);
   wcsutil_null_fill(72, wcs->ssysobs);
   wcsutil_null_fill(72, wcs->ssyssrc);
   wcsutil_null_fill(72, wcs->dateobs);
   wcsutil_null_fill(72, wcs->dateavg);
d2128 3
a2130 3
   wcs->flag = WCSSET;

   return 0;
d2133 1
d2135 10
a2144 1
int wcs_types(struct wcsprm *wcs)
d2147 150
a2296 39
   const int  nalias = 2;
   const char aliases [2][4] = {"NCP", "GLS"};

   char ctypei[16], pcode[4], requir[9], scode[4];
   int i, j, m, naxis, *ndx = 0x0, type;


   if (wcs == 0x0) return 1;

   /* Parse the CTYPEia keyvalues. */
   pcode[0]  = '\0';
   requir[0] = '\0';
   wcs->lng  = -1;
   wcs->lat  = -1;
   wcs->spec = -1;
   wcs->cubeface = -1;


   naxis = wcs->naxis;
   if (wcs->types) free(wcs->types);
   wcs->types = calloc(naxis, sizeof(int));

   for (i = 0; i < naxis; i++) {
      /* Null fill. */
      wcsutil_null_fill(72, wcs->ctype[i]);

      strncpy(ctypei, wcs->ctype[i], 15);
      ctypei[15] = '\0';


      /* Logarithmic or tabular axis? */
      wcs->types[i] = 0;
      if (strcmp(ctypei+4, "-LOG") == 0) {
         /* Logarithmic axis. */
         wcs->types[i] = 400;

      } else if (strcmp(ctypei+4, "-TAB") == 0) {
         /* Tabular axis. */
         wcs->types[i] = 500;
d2299 2
a2300 9
      if (wcs->types[i]) {
         /* Could have -LOG or -TAB with celestial or spectral types. */
         ctypei[4] = '\0';

         /* Take care of things like 'FREQ-LOG' or 'RA---TAB'. */
         for (j = 3; j >= 0; j--) {
            if (ctypei[j] != '-') break;
            ctypei[j] = '\0';
         }
d2302 2
d2306 3
a2308 19
      if (ctypei[4] != '-' || ctypei[8] != '\0') {
         /* Identify Stokes, celestial and spectral types. */
         if (strcmp(ctypei, "STOKES") == 0) {
            /* STOKES axis. */
            wcs->types[i] = 1100;

         } else if (strcmp(ctypei, "RA")  == 0 ||
             strcmp(ctypei+1, "LON") == 0 ||
             strcmp(ctypei+2, "LN")  == 0) {
            /* Longitude axis. */
            if (wcs->lng < 0) wcs->lng = i;
            wcs->types[i] += 2000;

         } else if (strcmp(ctypei,   "DEC") == 0 ||
                    strcmp(ctypei+1, "LAT") == 0 ||
                    strcmp(ctypei+2, "LT")  == 0) {
            /* Latitude axis. */
            if (wcs->lat < 0) wcs->lat = i;
            wcs->types[i] += 2001;
d2310 2
a2311 9
         } else if (strcmp(ctypei, "CUBEFACE") == 0) {
            /* CUBEFACE axis. */
            if (wcs->cubeface == -1) {
               wcs->types[i] = 2102;
               wcs->cubeface = i;
            } else {
               /* Multiple CUBEFACE axes! */
               return 4;
            }
d2313 3
a2315 7
         } else if (spctyp(ctypei, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
            /* Spectral axis. */
            if (wcs->spec < 0) wcs->spec = i;
            wcs->types[i] += 3000;
         }

         continue;
d2317 1
d2319 5
a2324 4
      /* CTYPEia is in "4-3" form; is it a recognized spectral type? */
      if (spctyp(ctypei, 0x0, scode, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
         /* Spectral axis found (possibly linear, e.g. FREQ-LSR). */
         wcs->types[i] = 3000;
d2326 12
a2337 3
         if (strcmp(scode, "   ") != 0) {
            /* Non-linear spectral axis found. */
            wcs->types[i] += 300;
d2339 4
a2342 4
            /* Check uniqueness. */
            if (wcs->spec >= 0) {
               return 4;
            }
d2344 1
a2344 2
            wcs->spec = i;
         }
d2346 12
a2357 2
         continue;
      }
d2359 68
a2426 85

      /* Is it a recognized celestial projection? */
      for (j = 0; j < prj_ncode; j++) {
         if (strncmp(ctypei+5, prj_codes[j], 3) == 0) break;
      }

      if (j == prj_ncode) {
         /* Not a standard projection code, maybe it's an alias. */
         for (j = 0; j < nalias; j++) {
            if (strncmp(ctypei+5, aliases[j], 3) == 0) break;
         }

         if (j == nalias) {
            /* Not a recognized algorithm code of any type. */
            wcs->types[i] = -1;
            return 4;
         }
      }

      /* Parse the celestial axis type. */
      wcs->types[i] = 2200;
      if (*pcode == '\0') {
         /* The first of the two celestial axes. */
         sprintf(pcode, "%.3s", ctypei+5);

         if (strncmp(ctypei, "RA--", 4) == 0) {
            wcs->lng = i;
            strcpy(wcs->lngtyp, "RA");
            strcpy(wcs->lattyp, "DEC");
            ndx = &wcs->lat;
            sprintf(requir, "DEC--%s", pcode);
         } else if (strncmp(ctypei, "DEC-", 4) == 0) {
            wcs->lat = i;
            strcpy(wcs->lngtyp, "RA");
            strcpy(wcs->lattyp, "DEC");
            ndx = &wcs->lng;
            sprintf(requir, "RA---%s", pcode);
         } else if (strncmp(ctypei+1, "LON", 3) == 0) {
            wcs->lng = i;
            sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
            sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
            ndx = &wcs->lat;
            sprintf(requir, "%s-%s", wcs->lattyp, pcode);
         } else if (strncmp(ctypei+1, "LAT", 3) == 0) {
            wcs->lat = i;
            sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
            sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
            ndx = &wcs->lng;
            sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
         } else if (strncmp(ctypei+2, "LN", 2) == 0) {
            wcs->lng = i;
            sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
            sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
            ndx = &wcs->lat;
            sprintf(requir, "%s-%s", wcs->lattyp, pcode);
         } else if (strncmp(ctypei+2, "LT", 2) == 0) {
            wcs->lat = i;
            sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
            sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
            ndx = &wcs->lng;
            sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
         } else {
            /* Unrecognized celestial type. */
            wcs->types[i] = -1;

            wcs->lng = -1;
            wcs->lat = -1;
            return 4;
         }

         if (wcs->lat >= 0) wcs->types[i]++;

      } else {
         /* Looking for the complementary celestial axis. */
         if (wcs->lat < 0) wcs->types[i]++;

         if (strncmp(ctypei, requir, 8) != 0) {
            /* Inconsistent projection types. */
            wcs->lng = -1;
            wcs->lat = -1;
            return 4;
         }

         *ndx = i;
         requir[0] = '\0';
d2428 1
a2428 1
   }
d2430 2
a2431 7
   /* Do we have a complementary pair of celestial axes? */
   if (strcmp(requir, "")) {
      /* Unmatched celestial axis. */
      wcs->lng = -1;
      wcs->lat = -1;
      return 4;
   }
d2433 5
a2437 10
   /* Table group numbers. */
   for (j = 0; j < wcs->ntab; j++) {
      for (m = 0; m < wcs->tab[j].M; m++) {
         i = wcs->tab[j].map[m];

         type = (wcs->types[i] / 100) % 10;
         if (type != 5) {
            return 4;
         }
         wcs->types[i] += 10 * j;
d2439 1
a2439 50
   }

   return 0;
}


int wcs_units(struct wcsprm *wcs)

{
   char ctype[9], units[16];
   int  i, j, naxis;
   double scale, offset, power;

   /* Initialize if required. */
   if (wcs == 0x0) return 1;

   naxis = wcs->naxis;
   for (i = 0; i < naxis; i++) {
      /* Use types set by wcs_types(). */
      switch (wcs->types[i]/1000) {
      case 2:
         /* Celestial axis. */
         strcpy(units, "deg");
         break;

      case 3:
         /* Spectral axis. */
         strncpy(ctype, wcs->ctype[i], 8);
         ctype[8] = '\0';
         spctyp(ctype, 0x0, 0x0, 0x0, units, 0x0, 0x0, 0x0);
         break;

      default:
         continue;
      }

      /* Tabular axis, CDELTia and CRVALia relate to indices. */
      if ((wcs->types[i]/100)%10 == 5) {
         continue;
      }

      wcsutil_null_fill(72, wcs->cunit[i]);
      if (wcs->cunit[i][0]) {
         if (wcsunits(wcs->cunit[i], units, &scale, &offset, &power)) {
            return 6;
         }

         if (scale != 1.0) {
            wcs->cdelt[i] *= scale;
            wcs->crval[i] *= scale;
d2441 2
a2442 3
            for (j = 0; j < naxis; j++) {
               *(wcs->cd + i*naxis + j) *= scale;
            }
d2444 2
a2445 2
            strcpy(wcs->cunit[i], units);
         }
d2447 4
d2452 2
a2453 1
         strcpy(wcs->cunit[i], units);
a2454 1
   }
d2456 11
a2466 2
   return 0;
}
d2468 16
a2483 1
/*--------------------------------------------------------------------------*/
d2485 15
a2499 10
int wcsp2s(
   struct wcsprm *wcs,
   int ncoord,
   int nelem,
   const double pixcrd[],
   double imgcrd[],
   double phi[],
   double theta[],
   double world[],
   int stat[])
d2501 7
a2507 13
{
   int    bits, face, i, iso_x, iso_y, istat, *istatp, itab, k, m, nx, ny,
          *statp, status, type;
   double crvali, offset;
   register double *img, *wrl;
   struct celprm *wcscel = &(wcs->cel);
   struct prjprm *wcsprj = &(wcscel->prj);

   /* Initialize if required. */
   if (wcs == 0x0) return 1;
   if (wcs->flag != WCSSET) {
      if ((status = wcsset(wcs))) return status;
   }
d2509 4
a2512 2
   /* Sanity check. */
   if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) return 4;
d2514 3
d2518 3
a2520 4
   /* Apply pixel-to-world linear transformation. */
   if ((status = linp2x(&(wcs->lin), ncoord, nelem, pixcrd, imgcrd))) {
      return status;
   }
d2522 5
a2526 13
   /* Initialize status vectors. */
   if (!(istatp = calloc(ncoord, sizeof(int)))) {
      return 2;
   }

   stat[0] = 0;
   wcsutil_setAli(ncoord, 1, stat);


   /* Convert intermediate world coordinates to world coordinates. */
   for (i = 0; i < wcs->naxis; i++) {
      /* Extract the second digit of the axis type code. */
      type = (wcs->types[i] / 100) % 10;
d2528 3
a2530 17
      if (type <= 1) {
         /* Linear or quantized coordinate axis. */
         img = imgcrd + i;
         wrl = world  + i;
         crvali = wcs->crval[i];
         for (k = 0; k < ncoord; k++) {
            *wrl = *img + crvali;
            img += nelem;
            wrl += nelem;
         }

      } else if (wcs->types[i] == 2200) {
         /* Convert celestial coordinates; do we have a CUBEFACE axis? */
         if (wcs->cubeface != -1) {
            /* Separation between faces. */
            if (wcsprj->r0 == 0.0) {
               offset = 90.0;
d2532 2
a2533 1
               offset = wcsprj->r0*PI/2.0;
d2535 1
d2537 23
a2559 36
            /* Lay out faces in a plane. */
            img = imgcrd;
            statp = stat;
            bits = (1 << i) | (1 << wcs->lat);
            for (k = 0; k < ncoord; k++, statp++) {
               face = (int)(*(img+wcs->cubeface) + 0.5);
               if (fabs(*(img+wcs->cubeface) - face) > 1e-10) {
                  *statp |= bits;
                  status = 8;

               } else {
                  *statp = 0;

                  switch (face) {
                  case 0:
                     *(img+wcs->lat) += offset;
                     break;
                  case 1:
                     break;
                  case 2:
                     *(img+i) += offset;
                     break;
                  case 3:
                     *(img+i) += offset*2;
                     break;
                  case 4:
                     *(img+i) += offset*3;
                     break;
                  case 5:
                     *(img+wcs->lat) -= offset;
                     break;
                  default:
                     *statp |= bits;
                     status = 8;
                  }
               }
d2561 1
a2561 3
               img += nelem;
            }
         }
d2563 6
a2568 23
         /* Check for constant x and/or y. */
         nx = ncoord;
         ny = 0;

         if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
            nx = 1;
            ny = ncoord;
         }
         if ((iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat))) {
            ny = 1;
         }

         /* Transform projection plane coordinates to celestial coordinates. */
         if ((istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                             imgcrd+wcs->lat, phi, theta, world+i,
                             world+wcs->lat, istatp))) {
            if (istat == 5) {
               status = 8;
            } else {
               status = istat + 3;
               goto cleanup;
            }
         }
d2570 31
a2600 36
         /* If x and y were both constant, replicate values. */
         if (iso_x && iso_y) {
            wcsutil_setAll(ncoord, nelem, world+i);
            wcsutil_setAll(ncoord, nelem, world+wcs->lat);
            wcsutil_setAll(ncoord, 1, phi);
            wcsutil_setAll(ncoord, 1, theta);
            wcsutil_setAli(ncoord, 1, istatp);
         }

         if (istat == 5) {
            bits = (1 << i) | (1 << wcs->lat);
            wcsutil_setBit(ncoord, istatp, bits, stat);
         }

      } else if (type == 3 || type == 4) {
         /* Check for constant x. */
         nx = ncoord;
         if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
            nx = 1;
         }

         istat = 0;
         if (wcs->types[i] == 3300) {
            /* Spectral coordinates. */
            istat = spcx2s(&(wcs->spc), nx, nelem, nelem, imgcrd+i, world+i,
                           istatp);

         } else if (type == 4) {
            /* Logarithmic coordinates. */
            istat = logx2s(wcs->crval[i], nx, nelem, nelem, imgcrd+i, world+i,
                           istatp);
         }

         if (istat) {
            if (istat == 3) {
               status = 8;
d2602 18
a2619 14
               status = istat + 3;
               goto cleanup;
            }
         }

         /* If x was constant, replicate values. */
         if (iso_x) {
            wcsutil_setAll(ncoord, nelem, world+i);
            wcsutil_setAli(ncoord, 1, istatp);
         }

         if (istat == 3) {
            wcsutil_setBit(ncoord, istatp, 1 << i, stat);
         }
d2621 1
a2621 1
   }
d2623 2
d2626 7
a2632 3
   /* Do tabular coordinates. */
   for (itab = 0; itab < wcs->ntab; itab++) {
      istat = tabx2s(wcs->tab + itab, ncoord, nelem, imgcrd, world, istatp);
d2634 12
a2645 12
      if (istat == 4) {
         status = 8;

         bits = 0;
         for (m = 0; m < wcs->tab[itab].M; m++) {
            bits |= 1 << wcs->tab[itab].map[m];
         }
         wcsutil_setBit(ncoord, istatp, bits, stat);

      } else if (istat) {
         status = (istat == 3) ? 5 : istat;
         goto cleanup;
a2646 1
   }
d2648 11
d2660 16
a2675 5
   /* Zero the unused world coordinate elements. */
   for (i = wcs->naxis; i < nelem; i++) {
      world[i] = 0.0;
      wcsutil_setAll(ncoord, nelem, world+i);
   }
d2677 14
a2690 85
cleanup:
   free(istatp);
   return status;
}

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

int wcss2p(
   struct wcsprm* wcs,
   int ncoord,
   int nelem,
   const double world[],
   double phi[],
   double theta[],
   double imgcrd[],
   double pixcrd[],
   int stat[])

{
   int    bits, i, isolat, isolng, isospec, istat, *istatp, itab, k, m, nlat,
          nlng, nwrld, status, type;
   double crvali, offset;
   register const double *wrl;
   register double *img;
   struct celprm *wcscel = &(wcs->cel);
   struct prjprm *wcsprj = &(wcscel->prj);


   /* Initialize if required. */
   status = 0;
   if (wcs == 0x0) return 1;
   if (wcs->flag != WCSSET) {
      if ((status = wcsset(wcs))) return status;
   }

   /* Sanity check. */
   if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) return 4;

   /* Initialize status vectors. */
   if (!(istatp = calloc(ncoord, sizeof(int)))) {
      return 2;
   }

   stat[0] = 0;
   wcsutil_setAli(ncoord, 1, stat);


   /* Convert world coordinates to intermediate world coordinates. */
   for (i = 0; i < wcs->naxis; i++) {
      /* Extract the second digit of the axis type code. */
      type = (wcs->types[i] / 100) % 10;

      if (type <= 1) {
         /* Linear or quantized coordinate axis. */
         wrl = world  + i;
         img = imgcrd + i;
         crvali = wcs->crval[i];
         for (k = 0; k < ncoord; k++) {
            *img = *wrl - crvali;
            wrl += nelem;
            img += nelem;
         }

      } else if (wcs->types[i] == 2200) {
         /* Celestial coordinates; check for constant lng and/or lat. */
         nlng = ncoord;
         nlat = 0;

         if ((isolng = wcsutil_allEq(ncoord, nelem, world+i))) {
            nlng = 1;
            nlat = ncoord;
         }
         if ((isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat))) {
            nlat = 1;
         }

         /* Transform celestial coordinates to projection plane coordinates. */
         if ((istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                             world+wcs->lat, phi, theta, imgcrd+i,
                             imgcrd+wcs->lat, istatp))) {
            if (istat == 6) {
               status = 9;
            } else {
               status = istat + 3;
               goto cleanup;
a2691 1
         }
d2693 6
a2698 21
         /* If lng and lat were both constant, replicate values. */
         if (isolng && isolat) {
            wcsutil_setAll(ncoord, nelem, imgcrd+i);
            wcsutil_setAll(ncoord, nelem, imgcrd+wcs->lat);
            wcsutil_setAll(ncoord, 1, phi);
            wcsutil_setAll(ncoord, 1, theta);
            wcsutil_setAli(ncoord, 1, istatp);
         }

         if (istat == 6) {
            bits = (1 << i) | (1 << wcs->lat);
            wcsutil_setBit(ncoord, istatp, bits, stat);
         }

         /* Do we have a CUBEFACE axis? */
         if (wcs->cubeface != -1) {
            /* Separation between faces. */
            if (wcsprj->r0 == 0.0) {
               offset = 90.0;
            } else {
               offset = wcsprj->r0*PI/2.0;
d2701 4
a2704 21
            /* Stack faces in a cube. */
            img = imgcrd;
            for (k = 0; k < ncoord; k++) {
               if (*(img+wcs->lat) < -0.5*offset) {
                  *(img+wcs->lat) += offset;
                  *(img+wcs->cubeface) = 5.0;
               } else if (*(img+wcs->lat) > 0.5*offset) {
                  *(img+wcs->lat) -= offset;
                  *(img+wcs->cubeface) = 0.0;
               } else if (*(img+i) > 2.5*offset) {
                  *(img+i) -= 3.0*offset;
                  *(img+wcs->cubeface) = 4.0;
               } else if (*(img+i) > 1.5*offset) {
                  *(img+i) -= 2.0*offset;
                  *(img+wcs->cubeface) = 3.0;
               } else if (*(img+i) > 0.5*offset) {
                  *(img+i) -= offset;
                  *(img+wcs->cubeface) = 2.0;
               } else {
                  *(img+wcs->cubeface) = 1.0;
               }
d2706 3
a2708 3
               img += nelem;
            }
         }
d2710 2
a2711 25
      } else if (type == 3 || type == 4) {
         /* Check for constancy. */
         nwrld = ncoord;
         if ((isospec = wcsutil_allEq(ncoord, nelem, world+i))) {
            nwrld = 1;
         }

         istat = 0;
         if (wcs->types[i] == 3300) {
            /* Spectral coordinates. */
            istat = spcs2x(&(wcs->spc), nwrld, nelem, nelem, world+i,
                           imgcrd+i, istatp);

         } else if (type == 4) {
            /* Logarithmic coordinates. */
            istat = logs2x(wcs->crval[i], nwrld, nelem, nelem, world+i,
                           imgcrd+i, istatp);
         }

         if (istat) {
            if (istat == 4) {
               status = 9;
            } else {
               status = istat + 3;
               goto cleanup;
a2712 67
         }

         /* If constant, replicate values. */
         if (isospec) {
            wcsutil_setAll(ncoord, nelem, imgcrd+i);
            wcsutil_setAli(ncoord, 1, istatp);
         }

         if (istat == 4) {
            wcsutil_setBit(ncoord, istatp, 1 << i, stat);
         }
      }
   }


   /* Do tabular coordinates. */
   for (itab = 0; itab < wcs->ntab; itab++) {
      istat = tabs2x(wcs->tab + itab, ncoord, nelem, world, imgcrd, istatp);

      if (istat == 5) {
         status = 9;

         bits = 0;
         for (m = 0; m < wcs->tab[itab].M; m++) {
            bits |= 1 << wcs->tab[itab].map[m];
         }
         wcsutil_setBit(ncoord, istatp, bits, stat);

      } else if (istat) {
         status = (istat == 3) ? 5 : istat;
         goto cleanup;
      }
   }


   /* Zero the unused intermediate world coordinate elements. */
   for (i = wcs->naxis; i < nelem; i++) {
      imgcrd[i] = 0.0;
      wcsutil_setAll(ncoord, nelem, imgcrd+i);
   }


   /* Apply world-to-pixel linear transformation. */
   if ((istat = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd))) {
      status = istat;
      goto cleanup;
   }

cleanup:
   free(istatp);
   return status;
}

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

int wcsmix(
   struct wcsprm *wcs,
   int mixpix,
   int mixcel,
   const double vspan[2],
   double vstep,
   int viter,
   double world[],
   double phi[],
   double theta[],
   double imgcrd[],
   double pixcrd[])
d2714 4
a2717 129
{
   const int niter = 60;
   int    crossed, istep, iter, j, k, nstep, retry, stat[1], status;
   const double tol  = 1.0e-10;
   const double tol2 = 100.0*tol;
   double *worldlat, *worldlng;
   double lambda, span[2], step;
   double pixmix;
   double dlng, lng, lng0, lng0m, lng1, lng1m;
   double dlat, lat, lat0, lat0m, lat1, lat1m;
   double d, d0, d0m, d1, d1m, dx = 0.0;
   double dabs, dmin, lmin;
   double dphi, phi0, phi1;
   struct celprm *wcscel = &(wcs->cel);
   struct wcsprm wcs0;

   /* Initialize if required. */
   if (wcs == 0x0) return 1;
   if (wcs->flag != WCSSET) {
      if ((status = wcsset(wcs))) return status;
   }

   worldlng = world + wcs->lng;
   worldlat = world + wcs->lat;


   /* Check vspan. */
   if (vspan[0] <= vspan[1]) {
      span[0] = vspan[0];
      span[1] = vspan[1];
   } else {
      /* Swap them. */
      span[0] = vspan[1];
      span[1] = vspan[0];
   }

   /* Check vstep. */
   step = fabs(vstep);
   if (step == 0.0) {
      step = (span[1] - span[0])/10.0;
      if (step > 1.0 || step == 0.0) step = 1.0;
   }

   /* Check viter. */
   nstep = viter;
   if (nstep < 5) {
      nstep = 5;
   } else if (nstep > 10) {
      nstep = 10;
   }

   /* Given pixel element. */
   pixmix = pixcrd[mixpix];

   /* Iterate on the step size. */
   for (istep = 0; istep <= nstep; istep++) {
      if (istep) step /= 2.0;

      /* Iterate on the sky coordinate between the specified range. */
      if (mixcel == 1) {
         /* Celestial longitude is given. */

         /* Check whether the solution interval is a crossing interval. */
         lat0 = span[0];
         *worldlat = lat0;
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
            return (status == 9) ? 10 : status;
         }
         d0 = pixcrd[mixpix] - pixmix;

         dabs = fabs(d0);
         if (dabs < tol) return 0;

         lat1 = span[1];
         *worldlat = lat1;
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
            return (status == 9) ? 10 : status;
         }
         d1 = pixcrd[mixpix] - pixmix;

         dabs = fabs(d1);
         if (dabs < tol) return 0;

         lmin = lat1;
         dmin = dabs;

         /* Check for a crossing point. */
         if (signbit(d0) != signbit(d1)) {
            crossed = 1;
            dx = d1;
         } else {
            crossed = 0;
            lat0 = span[1];
         }

         for (retry = 0; retry < 4; retry++) {
            /* Refine the solution interval. */
            while (lat0 > span[0]) {
               lat0 -= step;
               if (lat0 < span[0]) lat0 = span[0];
               *worldlat = lat0;
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
                  return (status == 9) ? 10 : status;
               }
               d0 = pixcrd[mixpix] - pixmix;

               /* Check for a solution. */
               dabs = fabs(d0);
               if (dabs < tol) return 0;

               /* Record the point of closest approach. */
               if (dabs < dmin) {
                  lmin = lat0;
                  dmin = dabs;
               }

               /* Check for a crossing point. */
               if (signbit(d0) != signbit(d1)) {
                  crossed = 2;
                  dx = d0;
                  break;
               }

               /* Advance to the next subinterval. */
               lat1 = lat0;
               d1 = d0;
d2720 3
a2722 53
            if (crossed) {
               /* A crossing point was found. */
               for (iter = 0; iter < niter; iter++) {
                  /* Use regula falsi division of the interval. */
                  lambda = d0/(d0-d1);
                  if (lambda < 0.1) {
                     lambda = 0.1;
                  } else if (lambda > 0.9) {
                     lambda = 0.9;
                  }

                  dlat = lat1 - lat0;
                  lat = lat0 + lambda*dlat;
                  *worldlat = lat;
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
                     return (status == 9) ? 10 : status;
                  }

                  /* Check for a solution. */
                  d = pixcrd[mixpix] - pixmix;
                  dabs = fabs(d);
                  if (dabs < tol) return 0;

                  if (dlat < tol) {
                     /* An artifact of numerical imprecision. */
                     if (dabs < tol2) return 0;

                     /* Must be a discontinuity. */
                     break;
                  }

                  /* Record the point of closest approach. */
                  if (dabs < dmin) {
                     lmin = lat;
                     dmin = dabs;
                  }

                  if (signbit(d0) == signbit(d)) {
                     lat0 = lat;
                     d0 = d;
                  } else {
                     lat1 = lat;
                     d1 = d;
                  }
               }

               /* No convergence, must have been a discontinuity. */
               if (crossed == 1) lat0 = span[1];
               lat1 = lat0;
               d1 = dx;
               crossed = 0;

d2724 2
a2725 64
               /* No crossing point; look for a tangent point. */
               if (lmin == span[0]) break;
               if (lmin == span[1]) break;

               lat = lmin;
               lat0 = lat - step;
               if (lat0 < span[0]) lat0 = span[0];
               lat1 = lat + step;
               if (lat1 > span[1]) lat1 = span[1];

               *worldlat = lat0;
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
                  return (status == 9) ? 10 : status;
               }
               d0 = fabs(pixcrd[mixpix] - pixmix);

               d  = dmin;

               *worldlat = lat1;
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
                  return (status == 9) ? 10 : status;
               }
               d1 = fabs(pixcrd[mixpix] - pixmix);

               for (iter = 0; iter < niter; iter++) {
                  lat0m = (lat0 + lat)/2.0;
                  *worldlat = lat0m;
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
                     return (status == 9) ? 10 : status;
                  }
                  d0m = fabs(pixcrd[mixpix] - pixmix);

                  if (d0m < tol) return 0;

                  lat1m = (lat1 + lat)/2.0;
                  *worldlat = lat1m;
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
                     return (status == 9) ? 10 : status;
                  }
                  d1m = fabs(pixcrd[mixpix] - pixmix);

                  if (d1m < tol) return 0;

                  if (d0m < d && d0m <= d1m) {
                     lat1 = lat;
                     d1   = d;
                     lat  = lat0m;
                     d    = d0m;
                  } else if (d1m < d) {
                     lat0 = lat;
                     d0   = d;
                     lat  = lat1m;
                     d    = d1m;
                  } else {
                     lat0 = lat0m;
                     d0   = d0m;
                     lat1 = lat1m;
                     d1   = d1m;
                  }
               }
d2727 1
a2727 4
         }

      } else {
         /* Celestial latitude is given. */
d2729 20
a2748 5
         /* Check whether the solution interval is a crossing interval. */
         lng0 = span[0];
         *worldlng = lng0;
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2750 2
a2751 2
         }
         d0 = pixcrd[mixpix] - pixmix;
d2753 1
a2753 2
         dabs = fabs(d0);
         if (dabs < tol) return 0;
d2755 3
a2757 4
         lng1 = span[1];
         *worldlng = lng1;
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2759 2
a2760 103
         }
         d1 = pixcrd[mixpix] - pixmix;

         dabs = fabs(d1);
         if (dabs < tol) return 0;
         lmin = lng1;
         dmin = dabs;

         /* Check for a crossing point. */
         if (signbit(d0) != signbit(d1)) {
            crossed = 1;
            dx = d1;
         } else {
            crossed = 0;
            lng0 = span[1];
         }

         for (retry = 0; retry < 4; retry++) {
            /* Refine the solution interval. */
            while (lng0 > span[0]) {
               lng0 -= step;
               if (lng0 < span[0]) lng0 = span[0];
               *worldlng = lng0;
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
                  return (status == 9) ? 10 : status;
               }
               d0 = pixcrd[mixpix] - pixmix;

               /* Check for a solution. */
               dabs = fabs(d0);
               if (dabs < tol) return 0;

               /* Record the point of closest approach. */
               if (dabs < dmin) {
                  lmin = lng0;
                  dmin = dabs;
               }

               /* Check for a crossing point. */
               if (signbit(d0) != signbit(d1)) {
                  crossed = 2;
                  dx = d0;
                  break;
               }

               /* Advance to the next subinterval. */
               lng1 = lng0;
               d1 = d0;
            }

            if (crossed) {
               /* A crossing point was found. */
               for (iter = 0; iter < niter; iter++) {
                  /* Use regula falsi division of the interval. */
                  lambda = d0/(d0-d1);
                  if (lambda < 0.1) {
                     lambda = 0.1;
                  } else if (lambda > 0.9) {
                     lambda = 0.9;
                  }

                  dlng = lng1 - lng0;
                  lng = lng0 + lambda*dlng;
                  *worldlng = lng;
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
                     return (status == 9) ? 10 : status;
                  }

                  /* Check for a solution. */
                  d = pixcrd[mixpix] - pixmix;
                  dabs = fabs(d);
                  if (dabs < tol) return 0;

                  if (dlng < tol) {
                     /* An artifact of numerical imprecision. */
                     if (dabs < tol2) return 0;

                     /* Must be a discontinuity. */
                     break;
                  }

                  /* Record the point of closest approach. */
                  if (dabs < dmin) {
                     lmin = lng;
                     dmin = dabs;
                  }

                  if (signbit(d0) == signbit(d)) {
                     lng0 = lng;
                     d0 = d;
                  } else {
                     lng1 = lng;
                     d1 = d;
                  }
               }

               /* No convergence, must have been a discontinuity. */
               if (crossed == 1) lng0 = span[1];
               lng1 = lng0;
               d1 = dx;
               crossed = 0;
d2762 31
d2794 62
a2855 69
               /* No crossing point; look for a tangent point. */
               if (lmin == span[0]) break;
               if (lmin == span[1]) break;

               lng = lmin;
               lng0 = lng - step;
               if (lng0 < span[0]) lng0 = span[0];
               lng1 = lng + step;
               if (lng1 > span[1]) lng1 = span[1];

               *worldlng = lng0;
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
                  return (status == 9) ? 10 : status;
               }
               d0 = fabs(pixcrd[mixpix] - pixmix);

               d  = dmin;

               *worldlng = lng1;
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
                  return (status == 9) ? 10 : status;
               }
               d1 = fabs(pixcrd[mixpix] - pixmix);

               for (iter = 0; iter < niter; iter++) {
                  lng0m = (lng0 + lng)/2.0;
                  *worldlng = lng0m;
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
                     return (status == 9) ? 10 : status;
                  }
                  d0m = fabs(pixcrd[mixpix] - pixmix);

                  if (d0m < tol) return 0;

                  lng1m = (lng1 + lng)/2.0;
                  *worldlng = lng1m;
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
                     return (status == 9) ? 10 : status;
                  }
                  d1m = fabs(pixcrd[mixpix] - pixmix);

                  if (d1m < tol) return 0;

                  if (d0m < d && d0m <= d1m) {
                     lng1 = lng;
                     d1   = d;
                     lng  = lng0m;
                     d    = d0m;
                  } else if (d1m < d) {
                     lng0 = lng;
                     d0   = d;
                     lng  = lng1m;
                     d    = d1m;
                  } else {
                     lng0 = lng0m;
                     d0   = d0m;
                     lng1 = lng1m;
                     d1   = d1m;
                  }
               }
            }
         }
      }
   }

d2857 5
a2861 37
   /* Set cel0 to the unity transformation. */
   wcs0 = *wcs;
   wcs0.cel.euler[0] = -90.0;
   wcs0.cel.euler[1] =   0.0;
   wcs0.cel.euler[2] =  90.0;
   wcs0.cel.euler[3] =   1.0;
   wcs0.cel.euler[4] =   0.0;

   /* No convergence, check for aberrant behaviour at a native pole. */
   *theta = -90.0;
   for (j = 1; j <= 2; j++) {
      /* Could the celestial coordinate element map to a native pole? */
      *phi = 0.0;
      *theta = -*theta;
      status = sphx2s(wcscel->euler, 1, 1, 1, 1, phi, theta, &lng, &lat);

      if (mixcel == 1) {
         if (fabs(fmod(*worldlng-lng, 360.0)) > tol) continue;
         if (lat < span[0]) continue;
         if (lat > span[1]) continue;
         *worldlat = lat;
      } else {
         if (fabs(*worldlat-lat) > tol) continue;
         if (lng < span[0]) lng += 360.0;
         if (lng > span[1]) lng -= 360.0;
         if (lng < span[0]) continue;
         if (lng > span[1]) continue;
         *worldlng = lng;
      }

      /* Is there a solution for the given pixel coordinate element? */
      lng = *worldlng;
      lat = *worldlat;

      /* Feed native coordinates to wcss2p() with cel0 set to unity. */
      *worldlng = -180.0;
      *worldlat = *theta;
d2864 1
a2864 1
         return (status == 9) ? 10 : status;
d2866 1
a2866 1
      d0 = pixcrd[mixpix] - pixmix;
d2869 22
a2890 5
      if (fabs(d0) < tol) {
         /* Recall saved world coordinates. */
         *worldlng = lng;
         *worldlat = lat;
         return 0;
d2893 6
a2898 10
      /* Search for a crossing interval. */
      phi0 = -180.0;
      for (k = -179; k <= 180; k++) {
         phi1 = (double) k;
         *worldlng = phi1;
         if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
            return (status == 9) ? 10 : status;
         }
         d1 = pixcrd[mixpix] - pixmix;
d2900 8
a2907 14
         /* Check for a solution. */
         dabs = fabs(d1);
         if (dabs < tol) {
            /* Recall saved world coordinates. */
            *worldlng = lng;
            *worldlat = lat;
            return 0;
         }

         /* Is it a crossing interval? */
         if (signbit(d0) != signbit(d1)) break;

         phi0 = phi1;
         d0 = d1;
d2910 6
a2915 33
      for (iter = 1; iter <= niter; iter++) {
         /* Use regula falsi division of the interval. */
         lambda = d0/(d0-d1);
         if (lambda < 0.1) {
            lambda = 0.1;
         } else if (lambda > 0.9) {
            lambda = 0.9;
         }

         dphi = phi1 - phi0;
         *worldlng = phi0 + lambda*dphi;
         if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
            return (status == 9) ? 10 : status;
         }

         /* Check for a solution. */
         d = pixcrd[mixpix] - pixmix;
         dabs = fabs(d);
         if (dabs < tol || (dphi < tol && dabs < tol2)) {
            /* Recall saved world coordinates. */
            *worldlng = lng;
            *worldlat = lat;
            return 0;
         }

         if (signbit(d0) == signbit(d)) {
            phi0 = *worldlng;
            d0 = d;
         } else {
            phi1 = *worldlng;
            d1 = d;
         }
d2917 2
a2918 1
   }
d2921 2
a2922 2
   /* No solution. */
   return 11;
d2928 3
a2930 3
   struct wcsprm *wcs,
   int  *i,
   char ctype[9])
d2933 47
a2979 48
   char   *code;
   int    j, status;
   double cdelt, crval;

   /* Initialize if required. */
   if (wcs == 0x0) return 1;
   if (wcs->flag != WCSSET) {
      if ((status = wcsset(wcs))) return status;
   }

   if ((j = *i) < 0 && (j = wcs->spec) < 0) {
      /* Look for a linear spectral axis. */
      for (j = 0; j < wcs->naxis; j++) {
         if (wcs->types[j]/100 == 30) {
            break;
         }
      }

      if (j >= wcs->naxis) {
         /* No spectral axis. */
         return 12;
      }

      *i = j;
   }

   /* Translate the spectral axis. */
   if ((status = spctrn(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                        wcs->restfrq, wcs->restwav, ctype, &crval,
                        &cdelt))) {
      return 6;
   }


   /* Translate keyvalues. */
   wcs->flag = 0;
   wcs->cdelt[j] = cdelt;
   wcs->crval[j] = crval;
   spctyp(ctype, 0x0, 0x0, 0x0, wcs->cunit[j], 0x0, 0x0, 0x0);

   /* Extract the Doppler frame from AIPS-convention types. */
   code = wcs->ctype[j] + 4;
   if (strcmp(code, "-LSR") == 0) {
      strcpy(wcs->specsys, "LSRK");
   } else if (strcmp(code, "-HEL") == 0) {
      strcpy(wcs->specsys, "BARYCENT");
   } else if (strcmp(code, "-OBS") == 0) {
      strcpy(wcs->specsys, "TOPOCENT");
@


4.3.1.1
log
@WCSLIB 4.3 development branch.
@
text
@d2 2
a3 2
    WCSLIB 4.4 - an implementation of the FITS WCS standard.
    Copyright (C) 1995-2008, Mark Calabretta
d30 1
a30 1
    $Id: wcs.c,v 4.3 2007/12/27 05:41:36 cal103 Exp cal103 $
@


4.3.1.2
log
@In wcsset(), guard against long strings when copying the projection code.
In wcs_types(), allow for early Paper IV distortion codes when parsing CTYPEia.
@
text
@d30 1
a30 1
    $Id: wcs.c,v 4.3.1.1 2007/12/27 13:23:47 cal103 Exp cal103 $
d1459 1
a1459 1
      } else if (strncmp(wcs->ctype[wcs->lng]+5, "NCP", 3) == 0) {
d1470 1
a1470 2
         strncpy(wcsprj->code, wcs->ctype[wcs->lng]+5, 3);
         wcsprj->code[3] = '\0';
a1637 11
      /* Check for early Paper IV syntax (e.g. '-SIP' used by Spitzer). */
      if (ctypei[8] == '-' && ctypei[12] == '\0') {
         /* Excise the "4-3-3" or "8-3"-form distortion code. */
         ctypei[8] = '\0';

         /* Remove trailing dashes from "8-3"-form codes. */
         for (j = 7; j > 0; j--) {
            if (ctypei[j] != '-') break;
            ctypei[j] = '\0';
         }
      }
d2945 2
a2946 1
                        wcs->restfrq, wcs->restwav, ctype, &crval, &cdelt))) {
@


4.3.1.3
log
@Bug fix in wcsset() for PROJPn and PVi_[34]a handling reported by
Hans Terlouw.  Refinement of previous fix in wcs_types().
@
text
@d30 1
a30 1
    $Id: wcs.c,v 4.3.1.2 2008/07/17 05:52:08 cal103 Exp cal103 $
d1417 1
a1417 1
         if (i == -1) {
d1640 1
a1640 1
      if (strlen(ctypei) == 12 && ctypei[8] == '-') {
d1674 1
a1674 1
      if (!(strlen(ctypei) == 8 && ctypei[4] == '-')) {
@


4.3.1.4
log
@Changed indentation.
@
text
@d2 2
d5 1
a5 2
  WCSLIB 4.4 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2009, Mark Calabretta
d7 24
a30 26
  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: wcs.c,v 4.3.1.3 2008/09/09 01:57:09 cal103 Exp cal103 $
d60 14
a73 14
  "Success",
  "Null wcsprm pointer passed",
  "Memory allocation failed",
  "Linear transformation matrix is singular",
  "Inconsistent or unrecognized coordinate axis types",
  "Invalid parameter value",
  "Invalid coordinate transformation parameters",
  "Ill-conditioned coordinate transformation parameters",
  "One or more of the pixel coordinates were invalid",
  "One or more of the world coordinates were invalid",
  "Invalid world coordinate",
  "No solution found in the specified interval",
  "Invalid subimage specification",
  "Non-separable subimage coordinate system"};
d93 131
a223 2
  int i, j, k, status;
  double *cd;
d225 90
a314 1
  if (wcs == 0x0) return 1;
d316 33
a348 24
  if (naxis <= 0) {
    return 2;
  }

  /* Initialize memory management. */
  if (wcs->flag == -1 || wcs->m_flag != WCSSET) {
    wcs->m_flag  = 0;
    wcs->m_naxis = 0;
    wcs->m_crpix = 0x0;
    wcs->m_pc    = 0x0;
    wcs->m_cdelt = 0x0;
    wcs->m_crval = 0x0;
    wcs->m_cunit = 0x0;
    wcs->m_ctype = 0x0;
    wcs->m_pv    = 0x0;
    wcs->m_ps    = 0x0;
    wcs->m_cd    = 0x0;
    wcs->m_crota = 0x0;
    wcs->m_colax = 0x0;
    wcs->m_cname = 0x0;
    wcs->m_crder = 0x0;
    wcs->m_csyer = 0x0;
    wcs->m_tab   = 0x0;
    wcs->m_wtb   = 0x0;
d350 5
a354 4
    if (wcs->flag == -1) {
      wcs->lin.flag = -1;
    }
  }
d356 10
a365 1
  if (wcs->flag == -1) wcs->types = 0x0;
d367 5
d373 10
a382 31
  /* Allocate memory for arrays if required. */
  if (alloc ||
     wcs->crpix == 0x0 ||
     wcs->pc    == 0x0 ||
     wcs->cdelt == 0x0 ||
     wcs->crval == 0x0 ||
     wcs->cunit == 0x0 ||
     wcs->ctype == 0x0 ||
     (NPVMAX && wcs->pv == 0x0) ||
     (NPSMAX && wcs->ps == 0x0) ||
     wcs->cd    == 0x0 ||
     wcs->crota == 0x0 ||
     wcs->colax == 0x0 ||
     wcs->cname == 0x0 ||
     wcs->crder == 0x0 ||
     wcs->csyer == 0x0) {

    /* Was sufficient allocated previously? */
    if (wcs->m_flag == WCSSET &&
       (wcs->m_naxis < naxis  ||
        wcs->npvmax  < NPVMAX ||
        wcs->npsmax  < NPSMAX)) {
      /* No, free it. */
      wcsfree(wcs);
    }


    if (alloc || wcs->crpix == 0x0) {
      if (wcs->m_crpix) {
        /* In case the caller fiddled with it. */
        wcs->crpix = wcs->m_crpix;
d384 23
a406 15
      } else {
        if (!(wcs->crpix = calloc(naxis, sizeof(double)))) {
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crpix = wcs->crpix;
      }
    }

    if (alloc || wcs->pc == 0x0) {
      if (wcs->m_pc) {
        /* In case the caller fiddled with it. */
        wcs->pc = wcs->m_pc;
a407 16
      } else {
        if (!(wcs->pc = calloc(naxis*naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_pc    = wcs->pc;
      }
    }

    if (alloc || wcs->cdelt == 0x0) {
      if (wcs->m_cdelt) {
        /* In case the caller fiddled with it. */
        wcs->cdelt = wcs->m_cdelt;
d409 2
a410 16
      } else {
        if (!(wcs->cdelt = calloc(naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cdelt = wcs->cdelt;
      }
    }

    if (alloc || wcs->crval == 0x0) {
      if (wcs->m_crval) {
        /* In case the caller fiddled with it. */
        wcs->crval = wcs->m_crval;
a411 16
      } else {
        if (!(wcs->crval = calloc(naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crval = wcs->crval;
      }
    }

    if (alloc || wcs->cunit == 0x0) {
      if (wcs->m_cunit) {
        /* In case the caller fiddled with it. */
        wcs->cunit = wcs->m_cunit;
d413 8
a420 16
      } else {
        if (!(wcs->cunit = calloc(naxis, sizeof(char [72])))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cunit = wcs->cunit;
      }
    }

    if (alloc || wcs->ctype == 0x0) {
      if (wcs->m_ctype) {
        /* In case the caller fiddled with it. */
        wcs->ctype = wcs->m_ctype;
a421 16
      } else {
        if (!(wcs->ctype = calloc(naxis, sizeof(char [72])))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_ctype = wcs->ctype;
      }
    }

    if (alloc || wcs->pv == 0x0) {
      if (wcs->m_pv) {
        /* In case the caller fiddled with it. */
        wcs->pv = wcs->m_pv;
d423 4
a426 22
      } else {
        if (NPVMAX) {
          if (!(wcs->pv = calloc(NPVMAX, sizeof(struct pvcard)))) {
            wcsfree(wcs);
            return 2;
          }
        } else {
          wcs->pv = (struct pvcard *)0;
        }

        wcs->npvmax  = NPVMAX;

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_pv    = wcs->pv;
      }
    }

    if (alloc || wcs->ps == 0x0) {
      if (wcs->m_ps) {
        /* In case the caller fiddled with it. */
        wcs->ps = wcs->m_ps;
a427 22
      } else {
        if (NPSMAX) {
          if (!(wcs->ps = calloc(NPSMAX, sizeof(struct pscard)))) {
            wcsfree(wcs);
            return 2;
          }
        } else {
          wcs->ps = (struct pscard *)0;
        }

        wcs->npsmax  = NPSMAX;

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_ps    = wcs->ps;
      }
    }

    if (alloc || wcs->cd == 0x0) {
      if (wcs->m_cd) {
        /* In case the caller fiddled with it. */
        wcs->cd = wcs->m_cd;
d429 5
a433 16
      } else {
        if (!(wcs->cd = calloc(naxis*naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cd    = wcs->cd;
      }
    }

    if (alloc || wcs->crota == 0x0) {
      if (wcs->m_crota) {
        /* In case the caller fiddled with it. */
        wcs->crota = wcs->m_crota;
a434 16
      } else {
        if (!(wcs->crota = calloc(naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crota = wcs->crota;
      }
    }

    if (alloc || wcs->colax == 0x0) {
      if (wcs->m_colax) {
        /* In case the caller fiddled with it. */
        wcs->colax = wcs->m_colax;
d436 15
a450 16
      } else {
        if (!(wcs->colax = calloc(naxis, sizeof(int)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_colax = wcs->colax;
      }
    }

    if (alloc || wcs->cname == 0x0) {
      if (wcs->m_cname) {
        /* In case the caller fiddled with it. */
        wcs->cname = wcs->m_cname;
d452 6
a457 16
      } else {
        if (!(wcs->cname = calloc(naxis, sizeof(char [72])))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_cname = wcs->cname;
      }
    }

    if (alloc || wcs->crder == 0x0) {
      if (wcs->m_crder) {
        /* In case the caller fiddled with it. */
        wcs->crder = wcs->m_crder;
d459 11
a469 16
      } else {
        if (!(wcs->crder = calloc(naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_crder = wcs->crder;
      }
    }

    if (alloc || wcs->csyer == 0x0) {
      if (wcs->m_csyer) {
        /* In case the caller fiddled with it. */
        wcs->csyer = wcs->m_csyer;
d471 38
a508 114
      } else {
        if (!(wcs->csyer = calloc(naxis, sizeof(double)))) {
          wcsfree(wcs);
          return 2;
        }

        wcs->m_flag  = WCSSET;
        wcs->m_naxis = naxis;
        wcs->m_csyer = wcs->csyer;
      }
    }
  }


  wcs->flag  = 0;
  wcs->naxis = naxis;


  /* Set defaults for the linear transformation. */
  wcs->lin.crpix  = wcs->crpix;
  wcs->lin.pc     = wcs->pc;
  wcs->lin.cdelt  = wcs->cdelt;
  wcs->lin.m_flag = 0;
  if ((status = linini(0, naxis, &(wcs->lin)))) {
    return status;
  }


  /* CRVALia defaults to 0.0. */
  for (i = 0; i < naxis; i++) {
    wcs->crval[i] = 0.0;
  }


  /* CUNITia and CTYPEia are blank by default. */
  for (i = 0; i < naxis; i++) {
    memset(wcs->cunit[i], 0, 72);
    memset(wcs->ctype[i], 0, 72);
  }


  /* Set defaults for the celestial transformation parameters. */
  wcs->lonpole = UNDEFINED;
  wcs->latpole = +90.0;

  /* Set defaults for the spectral transformation parameters. */
  wcs->restfrq =  0.0;
  wcs->restwav =  0.0;

  /* Default parameter values. */
  wcs->npv = 0;
  for (k = 0; k < wcs->npvmax; k++) {
    wcs->pv[k].i = 0;
    wcs->pv[k].m = 0;
    wcs->pv[k].value = 0.0;
  }

  wcs->nps = 0;
  for (k = 0; k < wcs->npsmax; k++) {
    wcs->ps[k].i = 0;
    wcs->ps[k].m = 0;
    memset(wcs->ps[k].value, 0, 72);
  }

  /* Defaults for alternate linear transformations. */
  wcs->altlin = 0;
  cd = wcs->cd;
  for (i = 0; i < naxis; i++) {
    for (j = 0; j < naxis; j++) {
      *(cd++) = 0.0;
    }
  }
  for (i = 0; i < naxis; i++) {
    wcs->crota[i] = 0.0;
  }

  /* Defaults for auxiliary coordinate system information. */
  memset(wcs->alt, 0, 4);
  wcs->alt[0] = ' ';
  wcs->colnum = 0;
  memset(wcs->wcsname, 0, 72);
  for (i = 0; i < naxis; i++) {
    wcs->colax[i] = 0;
    memset(wcs->cname[i], 0, 72);
    wcs->crder[i] = UNDEFINED;
    wcs->csyer[i] = UNDEFINED;
  }
  memset(wcs->radesys, 0, 72);
  wcs->equinox    = UNDEFINED;
  memset(wcs->specsys, 0, 72);
  memset(wcs->ssysobs, 0, 72);
  wcs->velosys    = UNDEFINED;
  memset(wcs->ssyssrc, 0, 72);
  wcs->zsource    = UNDEFINED;
  wcs->obsgeo[0]  = UNDEFINED;
  wcs->obsgeo[1]  = UNDEFINED;
  wcs->obsgeo[2]  = UNDEFINED;
  memset(wcs->dateobs, 0, 72);
  memset(wcs->dateavg, 0, 72);
  wcs->mjdobs     = UNDEFINED;
  wcs->mjdavg     = UNDEFINED;

  wcs->ntab = 0;
  wcs->tab  = 0x0;
  wcs->nwtb = 0;
  wcs->wtb  = 0x0;

  /* Reset derived values. */
  strcpy(wcs->lngtyp, "    ");
  strcpy(wcs->lattyp, "    ");
  wcs->lng  = -1;
  wcs->lat  = -1;
  wcs->spec = -1;
  wcs->cubeface = -1;
d510 2
a511 2
  celini(&(wcs->cel));
  spcini(&(wcs->spc));
d513 1
a513 1
  return 0;
d519 5
a523 5
  int alloc,
  const struct wcsprm *wcssrc,
  int *nsub,
  int axes[],
  struct wcsprm *wcsdst)
d526 14
a539 28
  char *c, ctypei[16];
  int  axis, cubeface, dealloc, dummy, i, itab, j, k, latitude, longitude, m,
       *map = 0x0, msub, naxis, npv, nps, other, spectral, status, stokes;
  const double *srcp;
  double *dstp;
  struct tabprm *tabp;

  if (wcssrc == 0x0) return 1;

  if ((naxis = wcssrc->naxis) <= 0) {
    return 2;
  }

  if (!(map = calloc(naxis, sizeof(int)))) {
    return 2;
  }

  if (nsub == 0x0) {
    nsub = &dummy;
    *nsub = naxis;
  } else if (*nsub == 0) {
    *nsub = naxis;
  }

  if ((dealloc = (axes == 0x0))) {
    /* Construct an index array. */
    if (!(axes = calloc(naxis, sizeof(int)))) {
      free(map);
d541 8
a548 1
    }
d550 5
a554 26
    for (i = 0; i < naxis; i++) {
      axes[i] = i+1;
    }
  }


  msub = 0;
  for (j = 0; j < *nsub; j++) {
    axis = axes[j];

    if (abs(axis) > 0x1000) {
      /* Subimage extraction by type. */
      k = abs(axis) & 0xFF;

      longitude = k & WCSSUB_LONGITUDE;
      latitude  = k & WCSSUB_LATITUDE;
      cubeface  = k & WCSSUB_CUBEFACE;
      spectral  = k & WCSSUB_SPECTRAL;
      stokes    = k & WCSSUB_STOKES;

      if ((other = (axis < 0))) {
        longitude = !longitude;
        latitude  = !latitude;
        cubeface  = !cubeface;
        spectral  = !spectral;
        stokes    = !stokes;
d558 123
a680 2
        strncpy (ctypei, (char *)(wcssrc->ctype + i), 8);
        ctypei[8] = '\0';
d682 42
a723 74
        /* Find the last non-blank character. */
        c = ctypei + 8;
        while (c-- > ctypei) {
          if (*c == ' ') *c = '\0';
          if (*c != '\0') break;
        }

        if (
          strcmp(ctypei,   "RA")  == 0 ||
          strcmp(ctypei+1, "LON") == 0 ||
          strcmp(ctypei+2, "LN")  == 0 ||
          strncmp(ctypei,   "RA---", 5) == 0 ||
          strncmp(ctypei+1, "LON-", 4) == 0 ||
          strncmp(ctypei+2, "LN-", 3) == 0) {
          if (!longitude) {
            continue;
          }

        } else if (
          strcmp(ctypei,   "DEC") == 0 ||
          strcmp(ctypei+1, "LAT") == 0 ||
          strcmp(ctypei+2, "LT")  == 0 ||
          strncmp(ctypei,   "DEC--", 5) == 0 ||
          strncmp(ctypei+1, "LAT-", 4) == 0 ||
          strncmp(ctypei+2, "LT-", 3) == 0) {
          if (!latitude) {
            continue;
          }

        } else if (strcmp(ctypei, "CUBEFACE") == 0) {
          if (!cubeface) {
            continue;
          }

        } else if ((
          strncmp(ctypei, "FREQ", 4) == 0 ||
          strncmp(ctypei, "ENER", 4) == 0 ||
          strncmp(ctypei, "WAVN", 4) == 0 ||
          strncmp(ctypei, "VRAD", 4) == 0 ||
          strncmp(ctypei, "WAVE", 4) == 0 ||
          strncmp(ctypei, "VOPT", 4) == 0 ||
          strncmp(ctypei, "ZOPT", 4) == 0 ||
          strncmp(ctypei, "AWAV", 4) == 0 ||
          strncmp(ctypei, "VELO", 4) == 0 ||
          strncmp(ctypei, "BETA", 4) == 0) &&
          (ctypei[4] == '\0' || ctypei[4] == '-')) {
          if (!spectral) {
            continue;
          }

        } else if (strcmp(ctypei, "STOKES") == 0) {
          if (!stokes) {
            continue;
          }

        } else if (!other) {
          continue;
        }

        /* This axis is wanted, but has it already been added? */
        for (k = 0; k < msub; k++) {
          if (map[k] == i+1) {
            break;
          }
        }
        if (k == msub) map[msub++] = i+1;
      }

    } else if (0 < axis && axis <= naxis) {
      /* Check that the requested axis has not already been added. */
      for (k = 0; k < msub; k++) {
        if (map[k] == axis) {
          break;
        }
d725 3
a727 1
      if (k == msub) map[msub++] = axis;
d729 4
a732 2
    } else {
      status = 12;
d734 10
a743 2
    }
  }
d745 8
a752 25
  if ((*nsub = msub) == 0) {
    status = 0;
    goto cleanup;
  }

  for (i = 0; i < *nsub; i++) {
    axes[i] = map[i];
  }


  /* Construct the inverse axis map. */
  for (i = 0; i < naxis; i++) {
    map[i] = 0;
  }

  for (i = 0; i < *nsub; i++) {
    map[axes[i]-1] = i+1;
  }

  /* Check that the subimage coordinate system is separable. */
  if (*nsub < naxis) {
    srcp = wcssrc->pc;
    for (i = 0; i < naxis; i++) {
      for (j = 0; j < naxis; j++) {
        if (*(srcp++) == 0.0 || j == i) continue;
d754 4
a757 52
        if ((map[i] == 0) != (map[j] == 0)) {
          status = 13;
          goto cleanup;
        }
      }
    }
  }


  /* Initialize the destination. */
  npv = NPVMAX;
  nps = NPSMAX;

  NPVMAX = 0;
  for (k = 0; k < wcssrc->npv; k++) {
    i = wcssrc->pv[k].i;
    if (i == 0 || (i > 0 && map[i-1])) {
      NPVMAX++;
    }
  }

  NPSMAX = 0;
  for (k = 0; k < wcssrc->nps; k++) {
    i = wcssrc->ps[k].i;
    if (i > 0 && map[i-1]) {
      NPSMAX++;
    }
  }

  status = wcsini(alloc, *nsub, wcsdst);

  NPVMAX = npv;
  NPSMAX = nps;

  if (status) {
    goto cleanup;
  }


  /* Linear transformation. */
  srcp = wcssrc->crpix;
  dstp = wcsdst->crpix;
  for (j = 0; j < *nsub; j++) {
    k = axes[j] - 1;
    *(dstp++) = *(srcp+k);
  }

  srcp = wcssrc->pc;
  dstp = wcsdst->pc;
  for (i = 0; i < *nsub; i++) {
    for (j = 0; j < *nsub; j++) {
      k = (axes[i]-1)*naxis + (axes[j]-1);
d759 1
a759 2
    }
  }
d761 5
a765 60
  srcp = wcssrc->cdelt;
  dstp = wcsdst->cdelt;
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    *(dstp++) = *(srcp+k);
  }

  /* Coordinate reference value. */
  srcp = wcssrc->crval;
  dstp = wcsdst->crval;
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    *(dstp++) = *(srcp+k);
  }

  /* Coordinate units and type. */
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    strncpy(wcsdst->cunit[i], wcssrc->cunit[k], 72);
    strncpy(wcsdst->ctype[i], wcssrc->ctype[k], 72);
  }

  /* Celestial and spectral transformation parameters. */
  wcsdst->lonpole = wcssrc->lonpole;
  wcsdst->latpole = wcssrc->latpole;
  wcsdst->restfrq = wcssrc->restfrq;
  wcsdst->restwav = wcssrc->restwav;

  /* Parameter values. */
  npv = 0;
  for (k = 0; k < wcssrc->npv; k++) {
    i = wcssrc->pv[k].i;
    if (i == 0 || (i > 0 && map[i-1])) {
      /* i == 0 is a special code for the latitude axis. */
      wcsdst->pv[npv] = wcssrc->pv[k];
      wcsdst->pv[npv].i = map[i-1];
      npv++;
    }
  }
  wcsdst->npv = npv;

  nps = 0;
  for (k = 0; k < wcssrc->nps; k++) {
    i = wcssrc->ps[k].i;
    if (i > 0 && map[i-1]) {
      wcsdst->ps[nps] = wcssrc->ps[k];
      wcsdst->ps[nps].i = map[i-1];
      nps++;
    }
  }
  wcsdst->nps = nps;

  /* Alternate linear transformations. */
  wcsdst->altlin = wcssrc->altlin;

  srcp = wcssrc->cd;
  dstp = wcsdst->cd;
  for (i = 0; i < *nsub; i++) {
    for (j = 0; j < *nsub; j++) {
      k = (axes[i]-1)*naxis + (axes[j]-1);
d767 1
a767 2
    }
  }
d769 6
a774 57
  srcp = wcssrc->crota;
  dstp = wcsdst->crota;
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    *(dstp++) = *(srcp+k);
  }

  /* Auxiliary coordinate system information. */
  strncpy(wcsdst->alt, wcssrc->alt, 4);
  wcsdst->colnum = wcssrc->colnum;

  strncpy(wcsdst->wcsname, wcssrc->wcsname, 72);
  for (i = 0; i < *nsub; i++) {
    k = axes[i] - 1;
    wcsdst->colax[i] = wcssrc->colax[k];
    strncpy(wcsdst->cname[i], wcssrc->cname[k], 72);
    wcsdst->crder[i] = wcssrc->crder[k];
    wcsdst->csyer[i] = wcssrc->csyer[k];
  }

  strncpy(wcsdst->radesys, wcssrc->radesys, 72);
  wcsdst->equinox = wcssrc->equinox;

  strncpy(wcsdst->specsys, wcssrc->specsys, 72);
  strncpy(wcsdst->ssysobs, wcssrc->ssysobs, 72);
  wcsdst->velosys = wcssrc->velosys;
  strncpy(wcsdst->ssyssrc, wcssrc->ssyssrc, 72);
  wcsdst->zsource = wcssrc->zsource;

  wcsdst->obsgeo[0] = wcssrc->obsgeo[0];
  wcsdst->obsgeo[1] = wcssrc->obsgeo[1];
  wcsdst->obsgeo[2] = wcssrc->obsgeo[2];

  strncpy(wcsdst->dateobs, wcssrc->dateobs, 72);
  strncpy(wcsdst->dateavg, wcssrc->dateavg, 72);
  wcsdst->mjdobs = wcssrc->mjdobs;
  wcsdst->mjdavg = wcssrc->mjdavg;


  /* Coordinate lookup tables; only copy what's needed. */
  wcsdst->ntab = 0;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    /* Is this table wanted? */
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];

      if (map[i-1]) {
        wcsdst->ntab++;
        break;
      }
    }
  }

  if (wcsdst->ntab) {
    /* Allocate memory for tabprm structs. */
    if (!(wcsdst->tab = calloc(wcsdst->ntab, sizeof(struct tabprm)))) {
      wcsdst->ntab = 0;
d776 103
a878 3
      status = 2;
      goto cleanup;
    }
d880 2
a881 2
    wcsdst->m_tab = wcsdst->tab;
  }
d883 9
a891 9
  tabp = wcsdst->tab;
  for (itab = 0; itab < wcssrc->ntab; itab++) {
    for (m = 0; m < wcssrc->tab[itab].M; m++) {
      i = wcssrc->tab[itab].map[m];

      if (map[i-1]) {
        if ((status = tabcpy(1, wcssrc->tab + itab, tabp))) {
          goto cleanup;
        }
d893 3
a895 2
        tabp++;
        break;
d897 1
a897 2
    }
  }
d901 4
a904 4
  if (map) free(map);
  if (dealloc) {
    free(axes);
  }
d906 1
a906 1
  if (status && wcsdst->m_tab) free(wcsdst->m_tab);
d908 1
a908 1
  return status;
d916 3
a918 1
  int j;
d920 51
a970 1
  if (wcs == 0x0) return 1;
d972 4
a975 2
  if (wcs->flag == -1) {
    wcs->lin.flag = -1;
d977 21
a997 75
  } else {
    /* Free memory allocated by wcsini(). */
    if (wcs->m_flag == WCSSET) {
      if (wcs->crpix == wcs->m_crpix) wcs->crpix = 0x0;
      if (wcs->pc    == wcs->m_pc)    wcs->pc    = 0x0;
      if (wcs->cdelt == wcs->m_cdelt) wcs->cdelt = 0x0;
      if (wcs->crval == wcs->m_crval) wcs->crval = 0x0;
      if (wcs->cunit == wcs->m_cunit) wcs->cunit = 0x0;
      if (wcs->ctype == wcs->m_ctype) wcs->ctype = 0x0;
      if (wcs->pv    == wcs->m_pv)    wcs->pv    = 0x0;
      if (wcs->ps    == wcs->m_ps)    wcs->ps    = 0x0;
      if (wcs->cd    == wcs->m_cd)    wcs->cd    = 0x0;
      if (wcs->crota == wcs->m_crota) wcs->crota = 0x0;
      if (wcs->colax == wcs->m_colax) wcs->colax = 0x0;
      if (wcs->cname == wcs->m_cname) wcs->cname = 0x0;
      if (wcs->crder == wcs->m_crder) wcs->crder = 0x0;
      if (wcs->csyer == wcs->m_csyer) wcs->csyer = 0x0;
      if (wcs->tab   == wcs->m_tab)   wcs->tab   = 0x0;
      if (wcs->wtb   == wcs->m_wtb)   wcs->wtb   = 0x0;

      if (wcs->m_crpix)  free(wcs->m_crpix);
      if (wcs->m_pc)     free(wcs->m_pc);
      if (wcs->m_cdelt)  free(wcs->m_cdelt);
      if (wcs->m_crval)  free(wcs->m_crval);
      if (wcs->m_cunit)  free(wcs->m_cunit);
      if (wcs->m_ctype)  free(wcs->m_ctype);
      if (wcs->m_pv)     free(wcs->m_pv);
      if (wcs->m_ps)     free(wcs->m_ps);
      if (wcs->m_cd)     free(wcs->m_cd);
      if (wcs->m_crota)  free(wcs->m_crota);
      if (wcs->m_colax)  free(wcs->m_colax);
      if (wcs->m_cname)  free(wcs->m_cname);
      if (wcs->m_crder)  free(wcs->m_crder);
      if (wcs->m_csyer)  free(wcs->m_csyer);

      /* Free memory allocated by wcstab(). */
      if (wcs->m_tab) {
        for (j = 0; j < wcs->ntab; j++) {
          tabfree(wcs->m_tab + j);
        }

        free(wcs->m_tab);
      }
      if (wcs->m_wtb) free(wcs->m_wtb);
    }

    /* Free memory allocated by wcsset(). */
    if (wcs->types) free(wcs->types);

    if (wcs->lin.crpix == wcs->m_crpix) wcs->lin.crpix = 0x0;
    if (wcs->lin.pc    == wcs->m_pc)    wcs->lin.pc    = 0x0;
    if (wcs->lin.cdelt == wcs->m_cdelt) wcs->lin.cdelt = 0x0;
  }

  wcs->m_flag   = 0;
  wcs->m_naxis  = 0x0;
  wcs->m_crpix  = 0x0;
  wcs->m_pc     = 0x0;
  wcs->m_cdelt  = 0x0;
  wcs->m_crval  = 0x0;
  wcs->m_cunit  = 0x0;
  wcs->m_ctype  = 0x0;
  wcs->m_pv     = 0x0;
  wcs->m_ps     = 0x0;
  wcs->m_cd     = 0x0;
  wcs->m_crota  = 0x0;
  wcs->m_colax  = 0x0;
  wcs->m_cname  = 0x0;
  wcs->m_crder  = 0x0;
  wcs->m_csyer  = 0x0;

  wcs->ntab  = 0;
  wcs->m_tab = 0x0;
  wcs->nwtb  = 0;
  wcs->m_wtb = 0x0;
d999 1
a999 1
  wcs->types = 0x0;
d1001 1
a1001 1
  wcs->flag = 0;
d1003 1
a1003 1
  return linfree(&(wcs->lin));
d1011 2
a1012 2
  int i, j, k;
  struct wtbarr *wtbp;
d1014 1
a1014 1
  if (wcs == 0x0) return 1;
d1016 19
a1034 86
  if (wcs->flag != WCSSET) {
    printf("The wcsprm struct is UNINITIALIZED.\n");
    return 0;
  }

  printf("       flag: %d\n", wcs->flag);
  printf("      naxis: %d\n", wcs->naxis);
  printf("      crpix: %p\n", (void *)wcs->crpix);
  printf("            ");
  for (i = 0; i < wcs->naxis; i++) {
    printf("  %- 11.5g", wcs->crpix[i]);
  }
  printf("\n");

  /* Linear transformation. */
  k = 0;
  printf("         pc: %p\n", (void *)wcs->pc);
  for (i = 0; i < wcs->naxis; i++) {
    printf("    pc[%d][]:", i);
    for (j = 0; j < wcs->naxis; j++) {
      printf("  %- 11.5g", wcs->pc[k++]);
    }
    printf("\n");
  }

  /* Coordinate increment at reference point. */
  printf("      cdelt: %p\n", (void *)wcs->cdelt);
  printf("            ");
  for (i = 0; i < wcs->naxis; i++) {
    printf("  %- 11.5g", wcs->cdelt[i]);
  }
  printf("\n");

  /* Coordinate value at reference point. */
  printf("      crval: %p\n", (void *)wcs->crval);
  printf("            ");
  for (i = 0; i < wcs->naxis; i++) {
    printf("  %- 11.5g", wcs->crval[i]);
  }
  printf("\n");

  /* Coordinate units and type. */
  printf("      cunit: %p\n", (void *)wcs->cunit);
  for (i = 0; i < wcs->naxis; i++) {
    printf("             \"%s\"\n", wcs->cunit[i]);
  }

  printf("      ctype: %p\n", (void *)wcs->ctype);
  for (i = 0; i < wcs->naxis; i++) {
    printf("             \"%s\"\n", wcs->ctype[i]);
  }

  /* Celestial and spectral transformation parameters. */
  if (undefined(wcs->lonpole)) {
    printf("    lonpole: UNDEFINED\n");
  } else {
    printf("    lonpole: %9f\n", wcs->lonpole);
  }
  printf("    latpole: %9f\n", wcs->latpole);
  printf("    restfrq: %f\n", wcs->restfrq);
  printf("    restwav: %f\n", wcs->restwav);

  /* Parameter values. */
  printf("        npv: %d\n", wcs->npv);
  printf("     npvmax: %d\n", wcs->npvmax);
  printf("         pv: %p\n", (void *)wcs->pv);
  for (i = 0; i < wcs->npv; i++) {
    printf("             %3d%4d  %- 11.5g\n", (wcs->pv[i]).i,
      (wcs->pv[i]).m, (wcs->pv[i]).value);
  }
  printf("        nps: %d\n", wcs->nps);
  printf("     npsmax: %d\n", wcs->npsmax);
  printf("         ps: %p\n", (void *)wcs->ps);
  for (i = 0; i < wcs->nps; i++) {
    printf("             %3d%4d  %s\n", (wcs->ps[i]).i,
      (wcs->ps[i]).m, (wcs->ps[i]).value);
  }

  /* Alternate linear transformations. */
  printf("     altlin: %d\n", wcs->altlin);

  k = 0;
  printf("         cd: %p\n", (void *)wcs->cd);
  if (wcs->cd) {
    for (i = 0; i < wcs->naxis; i++) {
      printf("    cd[%d][]:", i);
d1036 1
a1036 1
        printf("  %- 11.5g", wcs->cd[k++]);
d1039 9
a1047 2
    }
  }
d1049 78
a1126 35
  printf("      crota: %p\n", (void *)wcs->crota);
  if (wcs->crota) {
    printf("            ");
    for (i = 0; i < wcs->naxis; i++) {
      printf("  %- 11.5g", wcs->crota[i]);
    }
    printf("\n");
  }

  /* Auxiliary coordinate system information. */
  printf("        alt: '%c'\n", wcs->alt[0]);
  printf("     colnum: %d\n", wcs->colnum);

  printf("      colax: %p\n", (void *)wcs->colax);
  if (wcs->colax) {
    printf("           ");
    for (i = 0; i < wcs->naxis; i++) {
      printf("  %5d", wcs->colax[i]);
    }
    printf("\n");
  }

  if (wcs->wcsname[0] == '\0') {
    printf("    wcsname: UNDEFINED\n");
  } else {
    printf("    wcsname: \"%s\"\n", wcs->wcsname);
  }

  printf("      cname: %p\n", (void *)wcs->cname);
  if (wcs->cname) {
    for (i = 0; i < wcs->naxis; i++) {
      if (wcs->cname[i][0] == '\0') {
        printf("             UNDEFINED\n");
      } else {
        printf("             \"%s\"\n", wcs->cname[i]);
d1128 8
a1135 2
    }
  }
d1137 8
a1144 8
  printf("      crder: %p\n", (void *)wcs->crder);
  if (wcs->crder) {
    printf("           ");
    for (i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->crder[i])) {
        printf("  UNDEFINED   ");
      } else {
        printf("  %- 11.5g", wcs->crder[i]);
d1146 11
a1156 12
    }
    printf("\n");
  }

  printf("      csyer: %p\n", (void *)wcs->csyer);
  if (wcs->csyer) {
    printf("           ");
    for (i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->csyer[i])) {
        printf("  UNDEFINED   ");
      } else {
        printf("  %- 11.5g", wcs->csyer[i]);
a1157 163
    }
    printf("\n");
  }

  if (wcs->radesys[0] == '\0') {
    printf("    radesys: UNDEFINED\n");
  } else {
    printf("    radesys: \"%s\"\n", wcs->radesys);
  }

  if (undefined(wcs->equinox)) {
    printf("    equinox: UNDEFINED\n");
  } else {
    printf("    equinox: %9f\n", wcs->equinox);
  }

  if (wcs->specsys[0] == '\0') {
    printf("    specsys: UNDEFINED\n");
  } else {
    printf("    specsys: \"%s\"\n", wcs->specsys);
  }

  if (wcs->ssysobs[0] == '\0') {
    printf("    ssysobs: UNDEFINED\n");
  } else {
    printf("    ssysobs: \"%s\"\n", wcs->ssysobs);
  }

  if (undefined(wcs->velosys)) {
    printf("    velosys: UNDEFINED\n");
  } else {
    printf("    velosys: %9f\n", wcs->velosys);
  }

  if (wcs->ssyssrc[0] == '\0') {
    printf("    ssyssrc: UNDEFINED\n");
  } else {
    printf("    ssyssrc: \"%s\"\n", wcs->ssyssrc);
  }

  if (undefined(wcs->zsource)) {
    printf("    zsource: UNDEFINED\n");
  } else {
    printf("    zsource: %9f\n", wcs->zsource);
  }

  printf("     obsgeo: ");
  for (i = 0; i < 3; i++) {
    if (undefined(wcs->obsgeo[i])) {
      printf("UNDEFINED     ");
    } else {
      printf("%- 11.5g  ", wcs->obsgeo[i]);
    }
  }
  printf("\n");

  if (wcs->dateobs[0] == '\0') {
    printf("    dateobs: UNDEFINED\n");
  } else {
    printf("    dateobs: \"%s\"\n", wcs->dateobs);
  }

  if (wcs->dateavg[0] == '\0') {
    printf("    dateavg: UNDEFINED\n");
  } else {
    printf("    dateavg: \"%s\"\n", wcs->dateavg);
  }

  if (undefined(wcs->mjdobs)) {
    printf("     mjdobs: UNDEFINED\n");
  } else {
    printf("     mjdobs: %9f\n", wcs->mjdobs);
  }

  if (undefined(wcs->mjdavg)) {
    printf("     mjdavg: UNDEFINED\n");
  } else {
    printf("     mjdavg: %9f\n", wcs->mjdavg);
  }

  printf("       ntab: %d\n", wcs->ntab);
  printf("        tab: %p", (void *)wcs->tab);
  if (wcs->tab != 0x0) printf("  (see below)");
  printf("\n");
  printf("       nwtb: %d\n", wcs->nwtb);
  printf("        wtb: %p", (void *)wcs->wtb);
  if (wcs->wtb != 0x0) printf("  (see below)");
  printf("\n");

  /* Derived values. */
  printf("      types: %p\n           ", (void *)wcs->types);
  for (i = 0; i < wcs->naxis; i++) {
    printf("%5d", wcs->types[i]);
  }
  printf("\n");

  printf("     lngtyp: \"%s\"\n", wcs->lngtyp);
  printf("     lattyp: \"%s\"\n", wcs->lattyp);
  printf("        lng: %d\n", wcs->lng);
  printf("        lat: %d\n", wcs->lat);
  printf("       spec: %d\n", wcs->spec);
  printf("   cubeface: %d\n", wcs->cubeface);

  printf("        lin: (see below)\n");
  printf("        cel: (see below)\n");
  printf("        spc: (see below)\n");

  /* Memory management. */
  printf("     m_flag: %d\n", wcs->m_flag);
  printf("    m_naxis: %d\n", wcs->m_naxis);
  printf("    m_crpix: %p", (void *)wcs->m_crpix);
  if (wcs->m_crpix == wcs->crpix) printf("  (= crpix)");
  printf("\n");
  printf("       m_pc: %p", (void *)wcs->m_pc);
  if (wcs->m_pc == wcs->pc) printf("  (= pc)");
  printf("\n");
  printf("    m_cdelt: %p", (void *)wcs->m_cdelt);
  if (wcs->m_cdelt == wcs->cdelt) printf("  (= cdelt)");
  printf("\n");
  printf("    m_crval: %p", (void *)wcs->m_crval);
  if (wcs->m_crval == wcs->crval) printf("  (= crval)");
  printf("\n");
  printf("    m_cunit: %p", (void *)wcs->m_cunit);
  if (wcs->m_cunit == wcs->cunit) printf("  (= cunit)");
  printf("\n");
  printf("    m_ctype: %p", (void *)wcs->m_ctype);
  if (wcs->m_ctype == wcs->ctype) printf("  (= ctype)");
  printf("\n");
  printf("       m_pv: %p", (void *)wcs->m_pv);
  if (wcs->m_pv == wcs->pv) printf("  (= pv)");
  printf("\n");
  printf("       m_ps: %p", (void *)wcs->m_ps);
  if (wcs->m_ps == wcs->ps) printf("  (= ps)");
  printf("\n");
  printf("       m_cd: %p", (void *)wcs->m_cd);
  if (wcs->m_cd == wcs->cd) printf("  (= cd)");
  printf("\n");
  printf("    m_crota: %p", (void *)wcs->m_crota);
  if (wcs->m_crota == wcs->crota) printf("  (= crota)");
  printf("\n");
  printf("\n");
  printf("    m_colax: %p", (void *)wcs->m_colax);
  if (wcs->m_colax == wcs->colax) printf("  (= colax)");
  printf("\n");
  printf("    m_cname: %p", (void *)wcs->m_cname);
  if (wcs->m_cname == wcs->cname) printf("  (= cname)");
  printf("\n");
  printf("    m_crder: %p", (void *)wcs->m_crder);
  if (wcs->m_crder == wcs->crder) printf("  (= crder)");
  printf("\n");
  printf("    m_csyer: %p", (void *)wcs->m_csyer);
  if (wcs->m_csyer == wcs->csyer) printf("  (= csyer)");
  printf("\n");
  printf("      m_tab: %p", (void *)wcs->m_tab);
  if (wcs->m_tab == wcs->tab) printf("  (= tab)");
  printf("\n");
  printf("      m_wtb: %p", (void *)wcs->m_wtb);
  if (wcs->m_wtb == wcs->wtb) printf("  (= wtb)");
  printf("\n");

  /* Tabular transformation parameters. */
  if ((wtbp = wcs->wtb)) {
    for (j = 0; j < wcs->nwtb; j++, wtbp++) {
d1159 1
a1159 15
      printf("wtb[%d].*\n", j);
      printf("          i: %d\n", wtbp->i);
      printf("          m: %d\n", wtbp->m);
      printf("       kind: %c\n", wtbp->kind);
      printf("     extnam: %s\n", wtbp->extnam);
      printf("     extver: %d\n", wtbp->extver);
      printf("     extlev: %d\n", wtbp->extlev);
      printf("      ttype: %s\n", wtbp->ttype);
      printf("        row: %ld\n", wtbp->row);
      printf("       ndim: %d\n", wtbp->ndim);
      printf("     dimlen: %p\n", (void *)wtbp->dimlen);
      printf("     arrayp: %p -> %p\n", (void *)wtbp->arrayp,
                                        (void *)(*(wtbp->arrayp)));
    }
  }
d1161 10
a1170 2
  if (wcs->tab) {
    for (j = 0; j < wcs->ntab; j++) {
d1172 1
a1172 19
      printf("tab[%d].*\n", j);
      tabprt(wcs->tab + j);
    }
  }

  /* Linear transformation parameters. */
  printf("\n");
  printf("   lin.*\n");
  linprt(&(wcs->lin));

  /* Celestial transformation parameters. */
  printf("\n");
  printf("   cel.*\n");
  celprt(&(wcs->cel));

  /* Spectral transformation parameters. */
  printf("\n");
  printf("   spc.*\n");
  spcprt(&(wcs->spc));
d1174 5
a1178 2
  return 0;
}
d1180 5
a1184 1
/*--------------------------------------------------------------------------*/
d1186 5
a1190 1
int wcsset(struct wcsprm *wcs)
d1192 5
a1196 220
{
  char scode[4], stype[5];
  int i, j, k, m, naxis, status;
  double lambda, rho;
  double *cd, *pc;
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);
  struct spcprm *wcsspc = &(wcs->spc);


  /* Determine axis types from CTYPEia. */
  if (wcs == 0x0) return 1;
  if ((status = wcs_types(wcs))) {
    return status;
  }

  /* Convert to canonical units. */
  if ((status = wcs_units(wcs))) {
    return status;
  }


  /* Non-linear celestial axes present? */
  if (wcs->lng >= 0 && wcs->types[wcs->lng] == 2200) {
    celini(wcscel);

    /* CRVALia, LONPOLEa, and LATPOLEa keyvalues. */
    wcscel->ref[0] = wcs->crval[wcs->lng];
    wcscel->ref[1] = wcs->crval[wcs->lat];
    wcscel->ref[2] = wcs->lonpole;
    wcscel->ref[3] = wcs->latpole;

    /* PVi_ma keyvalues. */
    for (k = 0; k < wcs->npv; k++) {
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;

      if (i == -1) {
        /* From a PROJPn keyword. */
        i = wcs->lat;
      }

      if (i == wcs->lat) {
        /* PVi_ma associated with latitude axis. */
        if (m < 30) {
          wcsprj->pv[m] = wcs->pv[k].value;
        }

      } else if (i == wcs->lng) {
        /* PVi_ma associated with longitude axis. */
        switch (m) {
        case 0:
          wcscel->offset = (wcs->pv[k].value != 0.0);
          break;
        case 1:
          wcscel->phi0   = wcs->pv[k].value;
          break;
        case 2:
          wcscel->theta0 = wcs->pv[k].value;
          break;
        case 3:
          /* If present, overrides LONPOLEa. */
          wcscel->ref[2] = wcs->pv[k].value;
          break;
        case 4:
          /* If present, overrides LATPOLEa. */
          wcscel->ref[3] = wcs->pv[k].value;
          break;
        default:
          return 6;
          break;
        }
      }
    }

    /* Do simple alias translations. */
    if (strncmp(wcs->ctype[wcs->lng]+5, "GLS", 3) == 0) {
      strcpy(wcsprj->code, "SFL");

    } else if (strncmp(wcs->ctype[wcs->lng]+5, "NCP", 3) == 0) {
      /* Convert NCP to SIN. */
      if (wcscel->ref[1] == 0.0) {
        return 5;
      }

      strcpy(wcsprj->code, "SIN");
      wcsprj->pv[1] = 0.0;
      wcsprj->pv[2] = cosd(wcscel->ref[1])/sind(wcscel->ref[1]);

    } else {
      strncpy(wcsprj->code, wcs->ctype[wcs->lng]+5, 3);
      wcsprj->code[3] = '\0';
    }

    /* Initialize the celestial transformation routines. */
    wcsprj->r0 = 0.0;
    if ((status = celset(wcscel))) {
      return status + 3;
    }

    /* Update LONPOLE, LATPOLE, and PVi_ma keyvalues. */
    wcs->lonpole = wcscel->ref[2];
    wcs->latpole = wcscel->ref[3];

    for (k = 0; k < wcs->npv; k++) {
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;

      if (i == wcs->lng) {
        switch (m) {
        case 1:
          wcs->pv[k].value = wcscel->phi0;
          break;
        case 2:
          wcs->pv[k].value = wcscel->theta0;
          break;
        case 3:
          wcs->pv[k].value = wcscel->ref[2];
          break;
        case 4:
          wcs->pv[k].value = wcscel->ref[3];
          break;
        }
      }
    }
  }


  /* Non-linear spectral axis present? */
  if (wcs->spec >= 0 && wcs->types[wcs->spec] == 3300) {
    spcini(wcsspc);
    spctyp(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0, 0x0, 0x0);
    strcpy(wcsspc->type, stype);
    strcpy(wcsspc->code, scode);

    /* CRVALia, RESTFRQa, and RESTWAVa keyvalues. */
    wcsspc->crval = wcs->crval[wcs->spec];
    wcsspc->restfrq = wcs->restfrq;
    wcsspc->restwav = wcs->restwav;

    /* PVi_ma keyvalues. */
    for (k = 0; k < wcs->npv; k++) {
      i = wcs->pv[k].i - 1;
      m = wcs->pv[k].m;

      if (i == wcs->spec) {
        /* PVi_ma associated with grism axis. */
        if (m < 7) {
          wcsspc->pv[m] = wcs->pv[k].value;
        }
      }
    }

    /* Initialize the spectral transformation routines. */
    if ((status = spcset(wcsspc))) {
      return status + 3;
    }
  }


  /* Tabular axes present? */
  for (j = 0; j < wcs->ntab; j++) {
    if ((status = tabset(wcs->tab + j))) {
      return status + 3;
    }
  }


  /* Initialize the linear transformation. */
  naxis = wcs->naxis;
  wcs->altlin &= 7;
  if (wcs->altlin > 1 && !(wcs->altlin & 1)) {
    pc = wcs->pc;

    if (wcs->altlin & 2) {
      /* Copy CDi_ja to PCi_ja and reset CDELTia. */
      cd = wcs->cd;
      for (i = 0; i < naxis; i++) {
        for (j = 0; j < naxis; j++) {
          *(pc++) = *(cd++);
        }
        wcs->cdelt[i] = 1.0;
      }

    } else if (wcs->altlin & 4) {
      /* Construct PCi_ja from CROTAia. */
      if ((i = wcs->lng) >= 0 && (j = wcs->lat) >= 0) {
        rho = wcs->crota[j];

        if (wcs->cdelt[i] == 0.0) return 3;
        lambda = wcs->cdelt[j]/wcs->cdelt[i];

        *(pc + i*naxis + i) = *(pc + j*naxis + j) = cosd(rho);
        *(pc + i*naxis + j) = *(pc + j*naxis + i) = sind(rho);
        *(pc + i*naxis + j) *= -lambda;
        *(pc + j*naxis + i) /=  lambda;
      }
    }
  }

  wcs->lin.crpix  = wcs->crpix;
  wcs->lin.pc     = wcs->pc;
  wcs->lin.cdelt  = wcs->cdelt;
  if ((status = linset(&(wcs->lin)))) {
    return status;
  }


  /* Strip off trailing blanks and null-fill auxiliary string members. */
  wcsutil_null_fill(4, wcs->alt);
  wcsutil_null_fill(72, wcs->wcsname);
  for (i = 0; i < naxis; i++) {
    wcsutil_null_fill(72, wcs->cname[i]);
  }
  wcsutil_null_fill(72, wcs->radesys);
  wcsutil_null_fill(72, wcs->specsys);
  wcsutil_null_fill(72, wcs->ssysobs);
  wcsutil_null_fill(72, wcs->ssyssrc);
  wcsutil_null_fill(72, wcs->dateobs);
  wcsutil_null_fill(72, wcs->dateavg);
d1198 5
a1202 1
  wcs->flag = WCSSET;
d1204 5
a1208 2
  return 0;
}
d1210 5
d1216 9
a1224 1
int wcs_types(struct wcsprm *wcs)
d1226 5
a1230 3
{
  const int  nalias = 2;
  const char aliases [2][4] = {"NCP", "GLS"};
d1232 5
a1236 2
  char ctypei[16], pcode[4], requir[9], scode[4];
  int i, j, m, naxis, *ndx = 0x0, type;
d1238 5
d1244 5
a1248 1
  if (wcs == 0x0) return 1;
d1250 15
a1264 179
  /* Parse the CTYPEia keyvalues. */
  pcode[0]  = '\0';
  requir[0] = '\0';
  wcs->lng  = -1;
  wcs->lat  = -1;
  wcs->spec = -1;
  wcs->cubeface = -1;


  naxis = wcs->naxis;
  if (wcs->types) free(wcs->types);
  wcs->types = calloc(naxis, sizeof(int));

  for (i = 0; i < naxis; i++) {
    /* Null fill. */
    wcsutil_null_fill(72, wcs->ctype[i]);

    strncpy(ctypei, wcs->ctype[i], 15);
    ctypei[15] = '\0';

    /* Check for early Paper IV syntax (e.g. '-SIP' used by Spitzer). */
    if (strlen(ctypei) == 12 && ctypei[8] == '-') {
      /* Excise the "4-3-3" or "8-3"-form distortion code. */
      ctypei[8] = '\0';

      /* Remove trailing dashes from "8-3"-form codes. */
      for (j = 7; j > 0; j--) {
        if (ctypei[j] != '-') break;
        ctypei[j] = '\0';
      }
    }

    /* Logarithmic or tabular axis? */
    wcs->types[i] = 0;
    if (strcmp(ctypei+4, "-LOG") == 0) {
      /* Logarithmic axis. */
      wcs->types[i] = 400;

    } else if (strcmp(ctypei+4, "-TAB") == 0) {
      /* Tabular axis. */
      wcs->types[i] = 500;
    }

    if (wcs->types[i]) {
      /* Could have -LOG or -TAB with celestial or spectral types. */
      ctypei[4] = '\0';

      /* Take care of things like 'FREQ-LOG' or 'RA---TAB'. */
      for (j = 3; j >= 0; j--) {
        if (ctypei[j] != '-') break;
        ctypei[j] = '\0';
      }
    }


    if (!(strlen(ctypei) == 8 && ctypei[4] == '-')) {
      /* Identify Stokes, celestial and spectral types. */
      if (strcmp(ctypei, "STOKES") == 0) {
        /* STOKES axis. */
        wcs->types[i] = 1100;

      } else if (strcmp(ctypei, "RA")  == 0 ||
        strcmp(ctypei+1, "LON") == 0 ||
        strcmp(ctypei+2, "LN")  == 0) {
        /* Longitude axis. */
        if (wcs->lng < 0) wcs->lng = i;
        wcs->types[i] += 2000;

      } else if (strcmp(ctypei,   "DEC") == 0 ||
                 strcmp(ctypei+1, "LAT") == 0 ||
                 strcmp(ctypei+2, "LT")  == 0) {
        /* Latitude axis. */
        if (wcs->lat < 0) wcs->lat = i;
        wcs->types[i] += 2001;

      } else if (strcmp(ctypei, "CUBEFACE") == 0) {
        /* CUBEFACE axis. */
        if (wcs->cubeface == -1) {
          wcs->types[i] = 2102;
          wcs->cubeface = i;
        } else {
          /* Multiple CUBEFACE axes! */
          return 4;
        }

      } else if (spctyp(ctypei, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
        /* Spectral axis. */
        if (wcs->spec < 0) wcs->spec = i;
        wcs->types[i] += 3000;
      }

      continue;
    }


    /* CTYPEia is in "4-3" form; is it a recognized spectral type? */
    if (spctyp(ctypei, 0x0, scode, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
      /* Spectral axis found (possibly linear, e.g. FREQ-LSR). */
      wcs->types[i] = 3000;

      if (strcmp(scode, "   ") != 0) {
        /* Non-linear spectral axis found. */
        wcs->types[i] += 300;

        /* Check uniqueness. */
        if (wcs->spec >= 0) {
          return 4;
        }

        wcs->spec = i;
      }

      continue;
    }


    /* Is it a recognized celestial projection? */
    for (j = 0; j < prj_ncode; j++) {
      if (strncmp(ctypei+5, prj_codes[j], 3) == 0) break;
    }

    if (j == prj_ncode) {
      /* Not a standard projection code, maybe it's an alias. */
      for (j = 0; j < nalias; j++) {
        if (strncmp(ctypei+5, aliases[j], 3) == 0) break;
      }

      if (j == nalias) {
        /* Not a recognized algorithm code of any type. */
        wcs->types[i] = -1;
        return 4;
      }
    }

    /* Parse the celestial axis type. */
    wcs->types[i] = 2200;
    if (*pcode == '\0') {
      /* The first of the two celestial axes. */
      sprintf(pcode, "%.3s", ctypei+5);

      if (strncmp(ctypei, "RA--", 4) == 0) {
        wcs->lng = i;
        strcpy(wcs->lngtyp, "RA");
        strcpy(wcs->lattyp, "DEC");
        ndx = &wcs->lat;
        sprintf(requir, "DEC--%s", pcode);
      } else if (strncmp(ctypei, "DEC-", 4) == 0) {
        wcs->lat = i;
        strcpy(wcs->lngtyp, "RA");
        strcpy(wcs->lattyp, "DEC");
        ndx = &wcs->lng;
        sprintf(requir, "RA---%s", pcode);
      } else if (strncmp(ctypei+1, "LON", 3) == 0) {
        wcs->lng = i;
        sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
        sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
        ndx = &wcs->lat;
        sprintf(requir, "%s-%s", wcs->lattyp, pcode);
      } else if (strncmp(ctypei+1, "LAT", 3) == 0) {
        wcs->lat = i;
        sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
        sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
        ndx = &wcs->lng;
        sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
      } else if (strncmp(ctypei+2, "LN", 2) == 0) {
        wcs->lng = i;
        sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
        sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
        ndx = &wcs->lat;
        sprintf(requir, "%s-%s", wcs->lattyp, pcode);
      } else if (strncmp(ctypei+2, "LT", 2) == 0) {
        wcs->lat = i;
        sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
        sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
        ndx = &wcs->lng;
        sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
      } else {
        /* Unrecognized celestial type. */
        wcs->types[i] = -1;
d1266 83
a1348 35
        wcs->lng = -1;
        wcs->lat = -1;
        return 4;
      }

      if (wcs->lat >= 0) wcs->types[i]++;

    } else {
      /* Looking for the complementary celestial axis. */
      if (wcs->lat < 0) wcs->types[i]++;

      if (strncmp(ctypei, requir, 8) != 0) {
        /* Inconsistent projection types. */
        wcs->lng = -1;
        wcs->lat = -1;
        return 4;
      }

      *ndx = i;
      requir[0] = '\0';
    }
  }

  /* Do we have a complementary pair of celestial axes? */
  if (strcmp(requir, "")) {
    /* Unmatched celestial axis. */
    wcs->lng = -1;
    wcs->lat = -1;
    return 4;
  }

  /* Table group numbers. */
  for (j = 0; j < wcs->ntab; j++) {
    for (m = 0; m < wcs->tab[j].M; m++) {
      i = wcs->tab[j].map[m];
d1350 5
a1354 3
      type = (wcs->types[i] / 100) % 10;
      if (type != 5) {
        return 4;
d1356 16
a1371 3
      wcs->types[i] += 10 * j;
    }
  }
d1373 1
a1373 1
  return 0;
d1376 1
d1378 1
a1378 1
int wcs_units(struct wcsprm *wcs)
d1381 7
a1387 53
  char ctype[9], units[16];
  int  i, j, naxis;
  double scale, offset, power;

  /* Initialize if required. */
  if (wcs == 0x0) return 1;

  naxis = wcs->naxis;
  for (i = 0; i < naxis; i++) {
    /* Use types set by wcs_types(). */
    switch (wcs->types[i]/1000) {
    case 2:
      /* Celestial axis. */
      strcpy(units, "deg");
      break;

    case 3:
      /* Spectral axis. */
      strncpy(ctype, wcs->ctype[i], 8);
      ctype[8] = '\0';
      spctyp(ctype, 0x0, 0x0, 0x0, units, 0x0, 0x0, 0x0);
      break;

    default:
      continue;
    }

    /* Tabular axis, CDELTia and CRVALia relate to indices. */
    if ((wcs->types[i]/100)%10 == 5) {
      continue;
    }

    wcsutil_null_fill(72, wcs->cunit[i]);
    if (wcs->cunit[i][0]) {
      if (wcsunits(wcs->cunit[i], units, &scale, &offset, &power)) {
        return 6;
      }

      if (scale != 1.0) {
        wcs->cdelt[i] *= scale;
        wcs->crval[i] *= scale;

        for (j = 0; j < naxis; j++) {
          *(wcs->cd + i*naxis + j) *= scale;
        }

        strcpy(wcs->cunit[i], units);
      }

    } else {
      strcpy(wcs->cunit[i], units);
    }
  }
a1388 2
  return 0;
}
d1390 5
a1394 1
/*--------------------------------------------------------------------------*/
d1396 4
a1399 10
int wcsp2s(
  struct wcsprm *wcs,
  int ncoord,
  int nelem,
  const double pixcrd[],
  double imgcrd[],
  double phi[],
  double theta[],
  double world[],
  int stat[])
a1400 67
{
  int    bits, face, i, iso_x, iso_y, istat, *istatp, itab, k, m, nx, ny,
        *statp, status, type;
  double crvali, offset;
  register double *img, *wrl;
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);

  /* Initialize if required. */
  if (wcs == 0x0) return 1;
  if (wcs->flag != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  /* Sanity check. */
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) return 4;


  /* Apply pixel-to-world linear transformation. */
  if ((status = linp2x(&(wcs->lin), ncoord, nelem, pixcrd, imgcrd))) {
    return status;
  }

  /* Initialize status vectors. */
  if (!(istatp = calloc(ncoord, sizeof(int)))) {
    return 2;
  }

  stat[0] = 0;
  wcsutil_setAli(ncoord, 1, stat);


  /* Convert intermediate world coordinates to world coordinates. */
  for (i = 0; i < wcs->naxis; i++) {
    /* Extract the second digit of the axis type code. */
    type = (wcs->types[i] / 100) % 10;

    if (type <= 1) {
      /* Linear or quantized coordinate axis. */
      img = imgcrd + i;
      wrl = world  + i;
      crvali = wcs->crval[i];
      for (k = 0; k < ncoord; k++) {
        *wrl = *img + crvali;
        img += nelem;
        wrl += nelem;
      }

    } else if (wcs->types[i] == 2200) {
      /* Convert celestial coordinates; do we have a CUBEFACE axis? */
      if (wcs->cubeface != -1) {
        /* Separation between faces. */
        if (wcsprj->r0 == 0.0) {
          offset = 90.0;
        } else {
          offset = wcsprj->r0*PI/2.0;
        }

        /* Lay out faces in a plane. */
        img = imgcrd;
        statp = stat;
        bits = (1 << i) | (1 << wcs->lat);
        for (k = 0; k < ncoord; k++, statp++) {
          face = (int)(*(img+wcs->cubeface) + 0.5);
          if (fabs(*(img+wcs->cubeface) - face) > 1e-10) {
            *statp |= bits;
            status = 8;
d1402 25
a1426 2
          } else {
            *statp = 0;
d1428 3
a1430 1
            switch (face) {
d1432 2
a1433 2
              *(img+wcs->lat) += offset;
              break;
d1435 2
a1436 1
              break;
d1438 2
a1439 2
              *(img+i) += offset;
              break;
d1441 3
a1443 2
              *(img+i) += offset*2;
              break;
d1445 3
a1447 5
              *(img+i) += offset*3;
              break;
            case 5:
              *(img+wcs->lat) -= offset;
              break;
d1449 2
a1450 2
              *statp |= bits;
              status = 8;
d1452 16
a1467 1
          }
d1469 3
a1471 2
          img += nelem;
        }
d1474 4
a1477 31
      /* Check for constant x and/or y. */
      nx = ncoord;
      ny = 0;

      if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
        nx = 1;
        ny = ncoord;
      }
      if ((iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat))) {
        ny = 1;
      }

      /* Transform projection plane coordinates to celestial coordinates. */
      if ((istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                          imgcrd+wcs->lat, phi, theta, world+i,
                          world+wcs->lat, istatp))) {
        if (istat == 5) {
          status = 8;
        } else {
          status = istat + 3;
          goto cleanup;
        }
      }

      /* If x and y were both constant, replicate values. */
      if (iso_x && iso_y) {
        wcsutil_setAll(ncoord, nelem, world+i);
        wcsutil_setAll(ncoord, nelem, world+wcs->lat);
        wcsutil_setAll(ncoord, 1, phi);
        wcsutil_setAll(ncoord, 1, theta);
        wcsutil_setAli(ncoord, 1, istatp);
d1480 51
a1530 3
      if (istat == 5) {
        bits = (1 << i) | (1 << wcs->lat);
        wcsutil_setBit(ncoord, istatp, bits, stat);
d1533 3
a1535 5
    } else if (type == 3 || type == 4) {
      /* Check for constant x. */
      nx = ncoord;
      if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
        nx = 1;
d1537 1
a1538 5
      istat = 0;
      if (wcs->types[i] == 3300) {
        /* Spectral coordinates. */
        istat = spcx2s(&(wcs->spc), nx, nelem, nelem, imgcrd+i, world+i,
                       istatp);
d1540 4
a1543 4
      } else if (type == 4) {
        /* Logarithmic coordinates. */
        istat = logx2s(wcs->crval[i], nx, nelem, nelem, imgcrd+i, world+i,
                       istatp);
d1545 18
d1564 13
a1576 7
      if (istat) {
        if (istat == 3) {
          status = 8;
        } else {
          status = istat + 3;
          goto cleanup;
        }
d1578 27
d1606 105
a1710 4
      /* If x was constant, replicate values. */
      if (iso_x) {
        wcsutil_setAll(ncoord, nelem, world+i);
        wcsutil_setAli(ncoord, 1, istatp);
d1713 19
a1731 2
      if (istat == 3) {
        wcsutil_setBit(ncoord, istatp, 1 << i, stat);
a1732 2
    }
  }
d1735 86
a1820 3
  /* Do tabular coordinates. */
  for (itab = 0; itab < wcs->ntab; itab++) {
    istat = tabx2s(wcs->tab + itab, ncoord, nelem, imgcrd, world, istatp);
d1822 7
a1828 2
    if (istat == 4) {
      status = 8;
d1830 10
a1839 3
      bits = 0;
      for (m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
d1841 1
a1841 1
      wcsutil_setBit(ncoord, istatp, bits, stat);
d1843 52
a1894 5
    } else if (istat) {
      status = (istat == 3) ? 5 : istat;
      goto cleanup;
    }
  }
d1896 2
d1899 4
a1902 5
  /* Zero the unused world coordinate elements. */
  for (i = wcs->naxis; i < nelem; i++) {
    world[i] = 0.0;
    wcsutil_setAll(ncoord, nelem, world+i);
  }
d1904 1
a1904 3
cleanup:
  free(istatp);
  return status;
d1909 10
a1918 10
int wcss2p(
  struct wcsprm* wcs,
  int ncoord,
  int nelem,
  const double world[],
  double phi[],
  double theta[],
  double imgcrd[],
  double pixcrd[],
  int stat[])
d1921 163
a2083 151
  int    bits, i, isolat, isolng, isospec, istat, *istatp, itab, k, m, nlat,
         nlng, nwrld, status, type;
  double crvali, offset;
  register const double *wrl;
  register double *img;
  struct celprm *wcscel = &(wcs->cel);
  struct prjprm *wcsprj = &(wcscel->prj);


  /* Initialize if required. */
  status = 0;
  if (wcs == 0x0) return 1;
  if (wcs->flag != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  /* Sanity check. */
  if (ncoord < 1 || (ncoord > 1 && nelem < wcs->naxis)) return 4;

  /* Initialize status vectors. */
  if (!(istatp = calloc(ncoord, sizeof(int)))) {
    return 2;
  }

  stat[0] = 0;
  wcsutil_setAli(ncoord, 1, stat);


  /* Convert world coordinates to intermediate world coordinates. */
  for (i = 0; i < wcs->naxis; i++) {
    /* Extract the second digit of the axis type code. */
    type = (wcs->types[i] / 100) % 10;

    if (type <= 1) {
      /* Linear or quantized coordinate axis. */
      wrl = world  + i;
      img = imgcrd + i;
      crvali = wcs->crval[i];
      for (k = 0; k < ncoord; k++) {
        *img = *wrl - crvali;
        wrl += nelem;
        img += nelem;
      }

    } else if (wcs->types[i] == 2200) {
      /* Celestial coordinates; check for constant lng and/or lat. */
      nlng = ncoord;
      nlat = 0;

      if ((isolng = wcsutil_allEq(ncoord, nelem, world+i))) {
        nlng = 1;
        nlat = ncoord;
      }
      if ((isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat))) {
        nlat = 1;
      }

      /* Transform celestial coordinates to projection plane coordinates. */
      if ((istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                          world+wcs->lat, phi, theta, imgcrd+i,
                          imgcrd+wcs->lat, istatp))) {
        if (istat == 6) {
          status = 9;
        } else {
          status = istat + 3;
          goto cleanup;
        }
      }

      /* If lng and lat were both constant, replicate values. */
      if (isolng && isolat) {
        wcsutil_setAll(ncoord, nelem, imgcrd+i);
        wcsutil_setAll(ncoord, nelem, imgcrd+wcs->lat);
        wcsutil_setAll(ncoord, 1, phi);
        wcsutil_setAll(ncoord, 1, theta);
        wcsutil_setAli(ncoord, 1, istatp);
      }

      if (istat == 6) {
        bits = (1 << i) | (1 << wcs->lat);
        wcsutil_setBit(ncoord, istatp, bits, stat);
      }

      /* Do we have a CUBEFACE axis? */
      if (wcs->cubeface != -1) {
        /* Separation between faces. */
        if (wcsprj->r0 == 0.0) {
          offset = 90.0;
        } else {
          offset = wcsprj->r0*PI/2.0;
        }

        /* Stack faces in a cube. */
        img = imgcrd;
        for (k = 0; k < ncoord; k++) {
          if (*(img+wcs->lat) < -0.5*offset) {
            *(img+wcs->lat) += offset;
            *(img+wcs->cubeface) = 5.0;
          } else if (*(img+wcs->lat) > 0.5*offset) {
            *(img+wcs->lat) -= offset;
            *(img+wcs->cubeface) = 0.0;
          } else if (*(img+i) > 2.5*offset) {
            *(img+i) -= 3.0*offset;
            *(img+wcs->cubeface) = 4.0;
          } else if (*(img+i) > 1.5*offset) {
            *(img+i) -= 2.0*offset;
            *(img+wcs->cubeface) = 3.0;
          } else if (*(img+i) > 0.5*offset) {
            *(img+i) -= offset;
            *(img+wcs->cubeface) = 2.0;
          } else {
            *(img+wcs->cubeface) = 1.0;
          }

          img += nelem;
        }
      }

    } else if (type == 3 || type == 4) {
      /* Check for constancy. */
      nwrld = ncoord;
      if ((isospec = wcsutil_allEq(ncoord, nelem, world+i))) {
        nwrld = 1;
      }

      istat = 0;
      if (wcs->types[i] == 3300) {
        /* Spectral coordinates. */
        istat = spcs2x(&(wcs->spc), nwrld, nelem, nelem, world+i,
                       imgcrd+i, istatp);

      } else if (type == 4) {
        /* Logarithmic coordinates. */
        istat = logs2x(wcs->crval[i], nwrld, nelem, nelem, world+i,
                       imgcrd+i, istatp);
      }

      if (istat) {
        if (istat == 4) {
          status = 9;
        } else {
          status = istat + 3;
          goto cleanup;
        }
      }

      /* If constant, replicate values. */
      if (isospec) {
        wcsutil_setAll(ncoord, nelem, imgcrd+i);
        wcsutil_setAli(ncoord, 1, istatp);
      }
d2085 9
a2093 2
      if (istat == 4) {
        wcsutil_setBit(ncoord, istatp, 1 << i, stat);
d2095 1
a2095 2
    }
  }
d2098 3
a2100 3
  /* Do tabular coordinates. */
  for (itab = 0; itab < wcs->ntab; itab++) {
    istat = tabs2x(wcs->tab + itab, ncoord, nelem, world, imgcrd, istatp);
d2102 2
a2103 2
    if (istat == 5) {
      status = 9;
d2105 9
a2113 3
      bits = 0;
      for (m = 0; m < wcs->tab[itab].M; m++) {
        bits |= 1 << wcs->tab[itab].map[m];
d2115 1
a2115 1
      wcsutil_setBit(ncoord, istatp, bits, stat);
a2116 5
    } else if (istat) {
      status = (istat == 3) ? 5 : istat;
      goto cleanup;
    }
  }
d2118 5
a2122 13

  /* Zero the unused intermediate world coordinate elements. */
  for (i = wcs->naxis; i < nelem; i++) {
    imgcrd[i] = 0.0;
    wcsutil_setAll(ncoord, nelem, imgcrd+i);
  }


  /* Apply world-to-pixel linear transformation. */
  if ((istat = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd))) {
    status = istat;
    goto cleanup;
  }
d2125 2
a2126 2
  free(istatp);
  return status;
d2131 10
a2140 12
int wcsmix(
  struct wcsprm *wcs,
  int mixpix,
  int mixcel,
  const double vspan[2],
  double vstep,
  int viter,
  double world[],
  double phi[],
  double theta[],
  double imgcrd[],
  double pixcrd[])
d2143 7
a2149 69
  const int niter = 60;
  int    crossed, istep, iter, j, k, nstep, retry, stat[1], status;
  const double tol  = 1.0e-10;
  const double tol2 = 100.0*tol;
  double *worldlat, *worldlng;
  double lambda, span[2], step;
  double pixmix;
  double dlng, lng, lng0, lng0m, lng1, lng1m;
  double dlat, lat, lat0, lat0m, lat1, lat1m;
  double d, d0, d0m, d1, d1m, dx = 0.0;
  double dabs, dmin, lmin;
  double dphi, phi0, phi1;
  struct celprm *wcscel = &(wcs->cel);
  struct wcsprm wcs0;

  /* Initialize if required. */
  if (wcs == 0x0) return 1;
  if (wcs->flag != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  worldlng = world + wcs->lng;
  worldlat = world + wcs->lat;


  /* Check vspan. */
  if (vspan[0] <= vspan[1]) {
    span[0] = vspan[0];
    span[1] = vspan[1];
  } else {
    /* Swap them. */
    span[0] = vspan[1];
    span[1] = vspan[0];
  }

  /* Check vstep. */
  step = fabs(vstep);
  if (step == 0.0) {
    step = (span[1] - span[0])/10.0;
    if (step > 1.0 || step == 0.0) step = 1.0;
  }

  /* Check viter. */
  nstep = viter;
  if (nstep < 5) {
    nstep = 5;
  } else if (nstep > 10) {
    nstep = 10;
  }

  /* Given pixel element. */
  pixmix = pixcrd[mixpix];

  /* Iterate on the step size. */
  for (istep = 0; istep <= nstep; istep++) {
    if (istep) step /= 2.0;

    /* Iterate on the sky coordinate between the specified range. */
    if (mixcel == 1) {
      /* Celestial longitude is given. */

      /* Check whether the solution interval is a crossing interval. */
      lat0 = span[0];
      *worldlat = lat0;
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        return (status == 9) ? 10 : status;
      }
      d0 = pixcrd[mixpix] - pixmix;
a2150 2
      dabs = fabs(d0);
      if (dabs < tol) return 0;
d2152 6
a2157 7
      lat1 = span[1];
      *worldlat = lat1;
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        return (status == 9) ? 10 : status;
      }
      d1 = pixcrd[mixpix] - pixmix;
d2159 2
a2160 2
      dabs = fabs(d1);
      if (dabs < tol) return 0;
d2162 4
a2165 2
      lmin = lat1;
      dmin = dabs;
d2167 2
a2168 8
      /* Check for a crossing point. */
      if (signbit(d0) != signbit(d1)) {
        crossed = 1;
        dx = d1;
      } else {
        crossed = 0;
        lat0 = span[1];
      }
a2169 11
      for (retry = 0; retry < 4; retry++) {
        /* Refine the solution interval. */
        while (lat0 > span[0]) {
          lat0 -= step;
          if (lat0 < span[0]) lat0 = span[0];
          *worldlat = lat0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            return (status == 9) ? 10 : status;
          }
          d0 = pixcrd[mixpix] - pixmix;
d2171 4
a2174 16
          /* Check for a solution. */
          dabs = fabs(d0);
          if (dabs < tol) return 0;

          /* Record the point of closest approach. */
          if (dabs < dmin) {
            lmin = lat0;
            dmin = dabs;
          }

          /* Check for a crossing point. */
          if (signbit(d0) != signbit(d1)) {
            crossed = 2;
            dx = d0;
            break;
          }
d2176 33
a2208 14
          /* Advance to the next subinterval. */
          lat1 = lat0;
          d1 = d0;
        }

        if (crossed) {
          /* A crossing point was found. */
          for (iter = 0; iter < niter; iter++) {
            /* Use regula falsi division of the interval. */
            lambda = d0/(d0-d1);
            if (lambda < 0.1) {
              lambda = 0.1;
            } else if (lambda > 0.9) {
              lambda = 0.9;
d2210 1
d2212 21
a2232 6
            dlat = lat1 - lat0;
            lat = lat0 + lambda*dlat;
            *worldlat = lat;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              return (status == 9) ? 10 : status;
d2235 21
a2255 8
            /* Check for a solution. */
            d = pixcrd[mixpix] - pixmix;
            dabs = fabs(d);
            if (dabs < tol) return 0;

            if (dlat < tol) {
              /* An artifact of numerical imprecision. */
              if (dabs < tol2) return 0;
d2257 1
a2257 2
              /* Must be a discontinuity. */
              break;
d2259 1
d2261 25
a2285 4
            /* Record the point of closest approach. */
            if (dabs < dmin) {
              lmin = lat;
              dmin = dabs;
d2287 1
d2289 11
a2299 8
            if (signbit(d0) == signbit(d)) {
              lat0 = lat;
              d0 = d;
            } else {
              lat1 = lat;
              d1 = d;
            }
          }
a2300 23
          /* No convergence, must have been a discontinuity. */
          if (crossed == 1) lat0 = span[1];
          lat1 = lat0;
          d1 = dx;
          crossed = 0;

        } else {
          /* No crossing point; look for a tangent point. */
          if (lmin == span[0]) break;
          if (lmin == span[1]) break;

          lat = lmin;
          lat0 = lat - step;
          if (lat0 < span[0]) lat0 = span[0];
          lat1 = lat + step;
          if (lat1 > span[1]) lat1 = span[1];

          *worldlat = lat0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            return (status == 9) ? 10 : status;
          }
          d0 = fabs(pixcrd[mixpix] - pixmix);
d2302 3
a2304 1
          d  = dmin;
d2306 2
a2307 6
          *worldlat = lat1;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
            return (status == 9) ? 10 : status;
          }
          d1 = fabs(pixcrd[mixpix] - pixmix);
d2309 9
a2317 50
          for (iter = 0; iter < niter; iter++) {
            lat0m = (lat0 + lat)/2.0;
            *worldlat = lat0m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              return (status == 9) ? 10 : status;
            }
            d0m = fabs(pixcrd[mixpix] - pixmix);

            if (d0m < tol) return 0;

            lat1m = (lat1 + lat)/2.0;
            *worldlat = lat1m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              return (status == 9) ? 10 : status;
            }
            d1m = fabs(pixcrd[mixpix] - pixmix);

            if (d1m < tol) return 0;

            if (d0m < d && d0m <= d1m) {
              lat1 = lat;
              d1   = d;
              lat  = lat0m;
              d    = d0m;
            } else if (d1m < d) {
              lat0 = lat;
              d0   = d;
              lat  = lat1m;
              d    = d1m;
            } else {
              lat0 = lat0m;
              d0   = d0m;
              lat1 = lat1m;
              d1   = d1m;
            }
          }
        }
      }

    } else {
      /* Celestial latitude is given. */

      /* Check whether the solution interval is a crossing interval. */
      lng0 = span[0];
      *worldlng = lng0;
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        return (status == 9) ? 10 : status;
d2319 71
a2389 1
      d0 = pixcrd[mixpix] - pixmix;
d2391 6
a2396 2
      dabs = fabs(d0);
      if (dabs < tol) return 0;
d2398 7
a2404 7
      lng1 = span[1];
      *worldlng = lng1;
      if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        return (status == 9) ? 10 : status;
      }
      d1 = pixcrd[mixpix] - pixmix;
d2406 2
a2407 13
      dabs = fabs(d1);
      if (dabs < tol) return 0;
      lmin = lng1;
      dmin = dabs;

      /* Check for a crossing point. */
      if (signbit(d0) != signbit(d1)) {
        crossed = 1;
        dx = d1;
      } else {
        crossed = 0;
        lng0 = span[1];
      }
d2409 13
a2421 8
      for (retry = 0; retry < 4; retry++) {
        /* Refine the solution interval. */
        while (lng0 > span[0]) {
          lng0 -= step;
          if (lng0 < span[0]) lng0 = span[0];
          *worldlng = lng0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
d2423 2
a2424 2
          }
          d0 = pixcrd[mixpix] - pixmix;
d2426 2
a2427 16
          /* Check for a solution. */
          dabs = fabs(d0);
          if (dabs < tol) return 0;

          /* Record the point of closest approach. */
          if (dabs < dmin) {
            lmin = lng0;
            dmin = dabs;
          }

          /* Check for a crossing point. */
          if (signbit(d0) != signbit(d1)) {
            crossed = 2;
            dx = d0;
            break;
          }
d2429 7
a2435 15
          /* Advance to the next subinterval. */
          lng1 = lng0;
          d1 = d0;
        }

        if (crossed) {
          /* A crossing point was found. */
          for (iter = 0; iter < niter; iter++) {
            /* Use regula falsi division of the interval. */
            lambda = d0/(d0-d1);
            if (lambda < 0.1) {
              lambda = 0.1;
            } else if (lambda > 0.9) {
              lambda = 0.9;
            }
d2437 2
a2438 7
            dlng = lng1 - lng0;
            lng = lng0 + lambda*dlng;
            *worldlng = lng;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              return (status == 9) ? 10 : status;
            }
d2440 2
a2441 4
            /* Check for a solution. */
            d = pixcrd[mixpix] - pixmix;
            dabs = fabs(d);
            if (dabs < tol) return 0;
d2443 41
a2483 6
            if (dlng < tol) {
              /* An artifact of numerical imprecision. */
              if (dabs < tol2) return 0;

              /* Must be a discontinuity. */
              break;
d2486 52
a2537 5
            /* Record the point of closest approach. */
            if (dabs < dmin) {
              lmin = lng;
              dmin = dabs;
            }
a2538 3
            if (signbit(d0) == signbit(d)) {
              lng0 = lng;
              d0 = d;
d2540 64
a2603 2
              lng1 = lng;
              d1 = d;
d2605 1
a2605 1
          }
d2607 8
a2614 20
          /* No convergence, must have been a discontinuity. */
          if (crossed == 1) lng0 = span[1];
          lng1 = lng0;
          d1 = dx;
          crossed = 0;

        } else {
          /* No crossing point; look for a tangent point. */
          if (lmin == span[0]) break;
          if (lmin == span[1]) break;

          lng = lmin;
          lng0 = lng - step;
          if (lng0 < span[0]) lng0 = span[0];
          lng1 = lng + step;
          if (lng1 > span[1]) lng1 = span[1];

          *worldlng = lng0;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
d2616 2
a2617 2
          }
          d0 = fabs(pixcrd[mixpix] - pixmix);
d2619 2
a2620 1
          d  = dmin;
d2622 4
a2625 3
          *worldlng = lng1;
          if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                               stat))) {
d2627 103
a2729 2
          }
          d1 = fabs(pixcrd[mixpix] - pixmix);
a2730 31
          for (iter = 0; iter < niter; iter++) {
            lng0m = (lng0 + lng)/2.0;
            *worldlng = lng0m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              return (status == 9) ? 10 : status;
            }
            d0m = fabs(pixcrd[mixpix] - pixmix);

            if (d0m < tol) return 0;

            lng1m = (lng1 + lng)/2.0;
            *worldlng = lng1m;
            if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                 stat))) {
              return (status == 9) ? 10 : status;
            }
            d1m = fabs(pixcrd[mixpix] - pixmix);

            if (d1m < tol) return 0;

            if (d0m < d && d0m <= d1m) {
              lng1 = lng;
              d1   = d;
              lng  = lng0m;
              d    = d0m;
            } else if (d1m < d) {
              lng0 = lng;
              d0   = d;
              lng  = lng1m;
              d    = d1m;
d2732 69
a2800 62
              lng0 = lng0m;
              d0   = d0m;
              lng1 = lng1m;
              d1   = d1m;
            }
          }
        }
      }
    }
  }


  /* Set cel0 to the unity transformation. */
  wcs0 = *wcs;
  wcs0.cel.euler[0] = -90.0;
  wcs0.cel.euler[1] =   0.0;
  wcs0.cel.euler[2] =  90.0;
  wcs0.cel.euler[3] =   1.0;
  wcs0.cel.euler[4] =   0.0;

  /* No convergence, check for aberrant behaviour at a native pole. */
  *theta = -90.0;
  for (j = 1; j <= 2; j++) {
    /* Could the celestial coordinate element map to a native pole? */
    *phi = 0.0;
    *theta = -*theta;
    status = sphx2s(wcscel->euler, 1, 1, 1, 1, phi, theta, &lng, &lat);

    if (mixcel == 1) {
      if (fabs(fmod(*worldlng-lng, 360.0)) > tol) continue;
      if (lat < span[0]) continue;
      if (lat > span[1]) continue;
      *worldlat = lat;
    } else {
      if (fabs(*worldlat-lat) > tol) continue;
      if (lng < span[0]) lng += 360.0;
      if (lng > span[1]) lng -= 360.0;
      if (lng < span[0]) continue;
      if (lng > span[1]) continue;
      *worldlng = lng;
    }

    /* Is there a solution for the given pixel coordinate element? */
    lng = *worldlng;
    lat = *worldlat;

    /* Feed native coordinates to wcss2p() with cel0 set to unity. */
    *worldlng = -180.0;
    *worldlat = *theta;
    if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                         stat))) {
      return (status == 9) ? 10 : status;
    }
    d0 = pixcrd[mixpix] - pixmix;

    /* Check for a solution. */
    if (fabs(d0) < tol) {
      /* Recall saved world coordinates. */
      *worldlng = lng;
      *worldlat = lat;
      return 0;
    }
d2802 37
a2838 5
    /* Search for a crossing interval. */
    phi0 = -180.0;
    for (k = -179; k <= 180; k++) {
      phi1 = (double) k;
      *worldlng = phi1;
d2841 1
a2841 1
        return (status == 9) ? 10 : status;
d2843 1
a2843 1
      d1 = pixcrd[mixpix] - pixmix;
d2846 5
a2850 22
      dabs = fabs(d1);
      if (dabs < tol) {
        /* Recall saved world coordinates. */
        *worldlng = lng;
        *worldlat = lat;
        return 0;
      }

      /* Is it a crossing interval? */
      if (signbit(d0) != signbit(d1)) break;

      phi0 = phi1;
      d0 = d1;
    }

    for (iter = 1; iter <= niter; iter++) {
      /* Use regula falsi division of the interval. */
      lambda = d0/(d0-d1);
      if (lambda < 0.1) {
        lambda = 0.1;
      } else if (lambda > 0.9) {
        lambda = 0.9;
d2853 25
a2877 5
      dphi = phi1 - phi0;
      *worldlng = phi0 + lambda*dphi;
      if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
        return (status == 9) ? 10 : status;
d2880 25
a2904 9
      /* Check for a solution. */
      d = pixcrd[mixpix] - pixmix;
      dabs = fabs(d);
      if (dabs < tol || (dphi < tol && dabs < tol2)) {
        /* Recall saved world coordinates. */
        *worldlng = lng;
        *worldlat = lat;
        return 0;
      }
d2906 7
a2912 6
      if (signbit(d0) == signbit(d)) {
        phi0 = *worldlng;
        d0 = d;
      } else {
        phi1 = *worldlng;
        d1 = d;
d2914 1
a2914 2
    }
  }
d2917 2
a2918 2
  /* No solution. */
  return 11;
d2924 3
a2926 3
  struct wcsprm *wcs,
  int  *i,
  char ctype[9])
d2929 47
a2975 47
  char   *code;
  int    j, status;
  double cdelt, crval;

  /* Initialize if required. */
  if (wcs == 0x0) return 1;
  if (wcs->flag != WCSSET) {
    if ((status = wcsset(wcs))) return status;
  }

  if ((j = *i) < 0 && (j = wcs->spec) < 0) {
    /* Look for a linear spectral axis. */
    for (j = 0; j < wcs->naxis; j++) {
      if (wcs->types[j]/100 == 30) {
        break;
      }
    }

    if (j >= wcs->naxis) {
      /* No spectral axis. */
      return 12;
    }

    *i = j;
  }

  /* Translate the spectral axis. */
  if ((status = spctrn(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                       wcs->restfrq, wcs->restwav, ctype, &crval, &cdelt))) {
    return 6;
  }


  /* Translate keyvalues. */
  wcs->flag = 0;
  wcs->cdelt[j] = cdelt;
  wcs->crval[j] = crval;
  spctyp(ctype, 0x0, 0x0, 0x0, wcs->cunit[j], 0x0, 0x0, 0x0);

  /* Extract the Doppler frame from AIPS-convention types. */
  code = wcs->ctype[j] + 4;
  if (strcmp(code, "-LSR") == 0) {
    strcpy(wcs->specsys, "LSRK");
  } else if (strcmp(code, "-HEL") == 0) {
    strcpy(wcs->specsys, "BARYCENT");
  } else if (strcmp(code, "-OBS") == 0) {
    strcpy(wcs->specsys, "TOPOCENT");
@


4.3.1.5
log
@Fixed the translation of GLS to SFL.  In the AIPS convention, setting the
reference longitude and latitude simply translates the reference point
(i.e. the map as a whole) to those coordinates without creating an oblique
grid.  This might be effected by adjusting CRPIXja but that is complicated
by the linear transformation and instead is accomplished here by setting
(phi_0,theta_0).
@
text
@d31 1
a31 1
  $Id: wcs.c,v 4.3.1.4 2009/07/22 04:28:39 cal103 Exp cal103 $
a1457 3
      wcscel->offset = 1;
      wcscel->phi0   = wcs->crval[wcs->lng];
      wcscel->theta0 = wcs->crval[wcs->lat];
@


4.2
log
@WCSLIB 4.2: moved wcs_allEq(), wcs_setAll(), and wcs_setAli() to wcsutil.{h,c}
as wcsutil_*(); simplified calls to calloc() in wcsini(); print the wtbarr
structs in wcsprt(); don't scale intermediate world coordinates by CUNITia in
wcs_units(); in wcsp2s() and wcss2p(), don't return prematurely in the tabular
coordinate loop, and ensure that stat[] elements once set are not reset and
set them as flag bits for each world coordinate element.
@
text
@d2 29
a30 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: wcs.c,v 4.1 2005/08/26 13:24:28 cal103 Exp cal103 $
d54 1
a54 1
/* Maximum number of PVi_ma and PSi_ma cards. */
d75 1
d77 1
d116 1
d143 1
d339 17
d418 1
a418 1
   if (status = linini(0, naxis, &(wcs->lin))) {
d477 1
d550 1
a550 1
   if (dealloc = (axes == 0x0)) {
d577 1
a577 1
         if (other = (axis < 0)) {
d832 1
d889 1
a889 1
            if (status = tabcpy(1, wcssrc->tab + itab, tabp)) {
d936 1
d953 1
d989 1
d1023 1
a1023 1
   printf("      crpix: 0x%x\n", (int)wcs->crpix);
d1032 1
a1032 1
   printf("         pc: 0x%x\n", (int)wcs->pc);
d1041 2
a1042 1
   printf("      cdelt: 0x%x\n", (int)wcs->cdelt);
d1049 2
a1050 2
   /* Coordinate reference value. */
   printf("      crval: 0x%x\n", (int)wcs->crval);
d1058 1
a1058 1
   printf("      cunit: 0x%x\n", (int)wcs->cunit);
d1063 1
a1063 1
   printf("      ctype: 0x%x\n", (int)wcs->ctype);
d1079 3
a1081 3
   printf("        npv: %d\n",  wcs->npv);
   printf("     npvmax: %d\n",  wcs->npvmax);
   printf("         pv: 0x%x\n", (int)wcs->pv);
d1086 3
a1088 3
   printf("        nps: %d\n",  wcs->nps);
   printf("     npsmax: %d\n",  wcs->npsmax);
   printf("         ps: 0x%x\n", (int)wcs->ps);
d1098 1
a1098 1
   printf("         cd: 0x%x\n", (int)wcs->cd);
d1109 1
a1109 1
   printf("      crota: 0x%x\n", (int)wcs->crota);
d1122 9
d1137 1
a1137 1
   printf("      cname: 0x%x\n", (int)wcs->cname);
d1148 1
a1148 1
   printf("      crder: 0x%x\n", (int)wcs->crder);
d1161 1
a1161 1
   printf("      csyer: 0x%x\n", (int)wcs->csyer);
d1251 1
a1251 1
   printf("        tab: 0x%x", (int)wcs->tab);
d1255 1
a1255 1
   printf("        wtb: 0x%x", (int)wcs->wtb);
d1260 1
a1260 1
   printf("      types: 0x%x\n           ", (int)wcs->types);
d1280 1
a1280 1
   printf("    m_crpix: 0x%x", (int)wcs->m_crpix);
d1283 1
a1283 1
   printf("       m_pc: 0x%x", (int)wcs->m_pc);
d1286 1
a1286 1
   printf("    m_cdelt: 0x%x", (int)wcs->m_cdelt);
d1289 1
a1289 1
   printf("    m_crval: 0x%x", (int)wcs->m_crval);
d1292 1
a1292 1
   printf("    m_cunit: 0x%x", (int)wcs->m_cunit);
d1295 1
a1295 1
   printf("    m_ctype: 0x%x", (int)wcs->m_ctype);
d1298 1
a1298 1
   printf("       m_pv: 0x%x", (int)wcs->m_pv);
d1301 1
a1301 1
   printf("       m_ps: 0x%x", (int)wcs->m_ps);
d1304 1
a1304 1
   printf("       m_cd: 0x%x", (int)wcs->m_cd);
d1307 1
a1307 1
   printf("    m_crota: 0x%x", (int)wcs->m_crota);
d1310 5
a1314 1
   printf("    m_cname: 0x%x", (int)wcs->m_cname);
d1317 1
a1317 1
   printf("    m_crder: 0x%x", (int)wcs->m_crder);
d1320 1
a1320 1
   printf("    m_csyer: 0x%x", (int)wcs->m_csyer);
d1323 1
a1323 1
   printf("      m_tab: 0x%x", (int)wcs->m_tab);
d1326 1
a1326 1
   printf("      m_wtb: 0x%x", (int)wcs->m_wtb);
d1331 1
a1331 1
   if (wtbp = wcs->wtb) {
d1344 3
a1346 3
         printf("     dimlen: 0x%x\n", (int)wtbp->dimlen);
         printf("     arrayp: 0x%x -> 0x%x\n", (int)wtbp->arrayp,
                                               (int)(*(wtbp->arrayp)));
d1392 1
a1392 1
   if (status = wcs_types(wcs)) {
d1397 1
a1397 1
   if (status = wcs_units(wcs)) {
d1406 1
a1406 1
      /* CRVALia, LONPOLEa, and LATPOLEa cards. */
d1412 1
a1412 1
      /* PVi_ma cards. */
d1418 1
a1418 1
            /* From a PROJPn card. */
d1441 1
a1441 1
               /* If present, overrides the LONPOLEa card. */
d1445 1
a1445 1
               /* If present, overrides the LATPOLEa card. */
d1475 1
a1475 1
      if (status = celset(wcscel)) {
d1479 1
a1479 1
      /* Update LONPOLE, LATPOLE, and PVi_ma cards. */
d1510 1
a1510 1
      spctyp(wcs->ctype[wcs->spec], stype, scode, 0, 0, 0, 0, 0);
d1514 1
a1514 1
      /* CRVALia, RESTFRQa, and RESTWAVa cards. */
d1519 1
a1519 1
      /* PVi_ma cards. */
d1533 1
a1533 1
      if (status = spcset(wcsspc)) {
d1541 1
a1541 1
      if (status = tabset(wcs->tab + j)) {
d1582 1
a1582 1
   if (status = linset(&(wcs->lin))) {
d1618 1
a1618 1
   /* Parse the CTYPEia cards. */
d1692 1
a1692 1
         } else if (spctyp(ctypei, 0, 0, 0, 0, 0, 0, 0) == 0) {
d1703 1
a1703 1
      if (spctyp(ctypei, 0, scode, 0, 0, 0, 0, 0) == 0) {
d1858 1
a1858 1
         spctyp(ctype, 0, 0, 0, units, 0, 0, 0);
d1886 3
d1919 1
a1919 1
      if (status = wcsset(wcs)) return status;
d1927 1
a1927 1
   if (status = linp2x(&(wcs->lin), ncoord, nelem, pixcrd, imgcrd)) {
d2011 1
a2011 1
         if (iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i)) {
d2015 1
a2015 1
         if (iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat)) {
d2020 3
a2022 3
         if (istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                            imgcrd+wcs->lat, phi, theta, world+i,
                            world+wcs->lat, istatp)) {
d2048 1
a2048 1
         if (iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i)) {
d2144 1
a2144 1
      if (status = wcsset(wcs)) return status;
d2180 1
a2180 1
         if (isolng = wcsutil_allEq(ncoord, nelem, world+i)) {
d2184 1
a2184 1
         if (isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat)) {
d2189 3
a2191 3
         if (istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                            world+wcs->lat, phi, theta, imgcrd+i,
                            imgcrd+wcs->lat, istatp)) {
d2252 1
a2252 1
         if (isospec = wcsutil_allEq(ncoord, nelem, world+i)) {
d2318 1
a2318 1
   if (istat = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd)) {
d2362 1
a2362 1
      if (status = wcsset(wcs)) return status;
d2408 2
a2409 2
         if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                             stat)) {
d2419 2
a2420 2
         if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                             stat)) {
d2446 2
a2447 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
d2488 2
a2489 2
                  if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                      pixcrd, stat)) {
d2539 2
a2540 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
d2548 2
a2549 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
d2557 2
a2558 2
                  if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                      pixcrd, stat)) {
d2567 2
a2568 2
                  if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                      pixcrd, stat)) {
d2601 2
a2602 2
         if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                             stat)) {
d2612 2
a2613 2
         if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                             stat)) {
d2638 2
a2639 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
d2680 2
a2681 2
                  if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                      pixcrd, stat)) {
d2731 2
a2732 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
d2740 2
a2741 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
d2749 2
a2750 2
                  if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                      pixcrd, stat)) {
d2759 2
a2760 2
                  if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                      pixcrd, stat)) {
d2827 2
a2828 2
      if (status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
d2846 2
a2847 2
         if (status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                             stat)) {
d2879 2
a2880 2
         if (status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                             stat)) {
d2924 1
a2924 1
      if (status = wcsset(wcs)) return status;
d2944 3
a2946 3
   if (status = spctrn(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                       wcs->restfrq, wcs->restwav, ctype, &crval,
                       &cdelt)) {
d2951 1
a2951 1
   /* Translate keyword values. */
d2955 1
a2955 1
   spctyp(ctype, 0, 0, 0, wcs->cunit[j], 0, 0, 0);
@


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: wcs.c,v 4.2 2005/09/22 12:23:27 cal103 Exp cal103 $
@


4.2.1.2
log
@Don't define the signbit macro if already defined (MacOSX).
@
text
@d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.1 2005/12/05 02:39:43 cal103 Exp cal103 $
a74 1
#ifndef signbit
a75 1
#endif
@


4.2.1.3
log
@In wcsprt(), 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: wcs.c,v 4.2.1.2 2005/12/05 02:43:23 cal103 Exp cal103 $
d999 1
a999 1
   printf("      crpix: %p\n", wcs->crpix);
d1008 1
a1008 1
   printf("         pc: %p\n", wcs->pc);
d1017 1
a1017 1
   printf("      cdelt: %p\n", wcs->cdelt);
d1025 1
a1025 1
   printf("      crval: %p\n", wcs->crval);
d1033 1
a1033 1
   printf("      cunit: %p\n", wcs->cunit);
d1038 1
a1038 1
   printf("      ctype: %p\n", wcs->ctype);
d1056 1
a1056 1
   printf("         pv: %p\n", wcs->pv);
d1063 1
a1063 1
   printf("         ps: %p\n", wcs->ps);
d1073 1
a1073 1
   printf("         cd: %p\n", wcs->cd);
d1084 1
a1084 1
   printf("      crota: %p\n", wcs->crota);
d1103 1
a1103 1
   printf("      cname: %p\n", wcs->cname);
d1114 1
a1114 1
   printf("      crder: %p\n", wcs->crder);
d1127 1
a1127 1
   printf("      csyer: %p\n", wcs->csyer);
d1217 1
a1217 1
   printf("        tab: %p", wcs->tab);
d1221 1
a1221 1
   printf("        wtb: %p", wcs->wtb);
d1226 1
a1226 1
   printf("      types: %p\n           ", wcs->types);
d1246 1
a1246 1
   printf("    m_crpix: %p", wcs->m_crpix);
d1249 1
a1249 1
   printf("       m_pc: %p", wcs->m_pc);
d1252 1
a1252 1
   printf("    m_cdelt: %p", wcs->m_cdelt);
d1255 1
a1255 1
   printf("    m_crval: %p", wcs->m_crval);
d1258 1
a1258 1
   printf("    m_cunit: %p", wcs->m_cunit);
d1261 1
a1261 1
   printf("    m_ctype: %p", wcs->m_ctype);
d1264 1
a1264 1
   printf("       m_pv: %p", wcs->m_pv);
d1267 1
a1267 1
   printf("       m_ps: %p", wcs->m_ps);
d1270 1
a1270 1
   printf("       m_cd: %p", wcs->m_cd);
d1273 1
a1273 1
   printf("    m_crota: %p", wcs->m_crota);
d1276 1
a1276 1
   printf("    m_cname: %p", wcs->m_cname);
d1279 1
a1279 1
   printf("    m_crder: %p", wcs->m_crder);
d1282 1
a1282 1
   printf("    m_csyer: %p", wcs->m_csyer);
d1285 1
a1285 1
   printf("      m_tab: %p", wcs->m_tab);
d1288 1
a1288 1
   printf("      m_wtb: %p", wcs->m_wtb);
d1306 3
a1308 2
         printf("     dimlen: %p\n", wtbp->dimlen);
         printf("     arrayp: %p -> %p\n", wtbp->arrayp, (*(wtbp->arrayp)));
@


4.2.1.4
log
@Added colax to the wcsprm struct to record the column numbers for each axis
in a pixel list.
@
text
@d4 1
a4 1
*   Copyright (C) 1995-2007, Mark Calabretta
d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.3 2006/06/01 07:31:33 cal103 Exp cal103 $
a115 1
      wcs->m_colax = 0x0;
a141 1
       wcs->colax == 0x0 ||
a336 17
      if (alloc || wcs->colax == 0x0) {
         if (wcs->m_colax) {
            /* In case the caller fiddled with it. */
            wcs->colax = wcs->m_colax;

         } else {
            if (!(wcs->colax = calloc(naxis, sizeof(int)))) {
               wcsfree(wcs);
               return 2;
            }

            wcs->m_flag  = WCSSET;
            wcs->m_naxis = naxis;
            wcs->m_colax = wcs->colax;
         }
      }

a457 1
      wcs->colax[i] = 0;
a811 1
      wcsdst->colax[i] = wcssrc->colax[k];
a914 1
         if (wcs->colax == wcs->m_colax) wcs->colax = 0x0;
a930 1
         if (wcs->m_colax)  free(wcs->m_colax);
a965 1
   wcs->m_colax  = 0x0;
a1096 9
   printf("      colax: %p\n", wcs->colax);
   if (wcs->colax) {
      printf("           ");
      for (i = 0; i < wcs->naxis; i++) {
         printf("  %5d", wcs->colax[i]);
      }
      printf("\n");
   }

a1275 3
   printf("\n");
   printf("    m_colax: %p", wcs->m_colax);
   if (wcs->m_colax == wcs->colax) printf("  (= colax)");
@


4.2.1.5
log
@Parenthesised assignments used as truth values.
@
text
@d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.4 2007/06/29 01:58:03 cal103 Exp cal103 $
d418 1
a418 1
   if ((status = linini(0, naxis, &(wcs->lin)))) {
d550 1
a550 1
   if ((dealloc = (axes == 0x0))) {
d577 1
a577 1
         if ((other = (axis < 0))) {
d889 1
a889 1
            if ((status = tabcpy(1, wcssrc->tab + itab, tabp))) {
d1329 1
a1329 1
   if ((wtbp = wcs->wtb)) {
d1389 1
a1389 1
   if ((status = wcs_types(wcs))) {
d1394 1
a1394 1
   if ((status = wcs_units(wcs))) {
d1472 1
a1472 1
      if ((status = celset(wcscel))) {
d1530 1
a1530 1
      if ((status = spcset(wcsspc))) {
d1538 1
a1538 1
      if ((status = tabset(wcs->tab + j))) {
d1579 1
a1579 1
   if ((status = linset(&(wcs->lin)))) {
d1913 1
a1913 1
      if ((status = wcsset(wcs))) return status;
d1921 1
a1921 1
   if ((status = linp2x(&(wcs->lin), ncoord, nelem, pixcrd, imgcrd))) {
d2005 1
a2005 1
         if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
d2009 1
a2009 1
         if ((iso_y = wcsutil_allEq(ncoord, nelem, imgcrd+wcs->lat))) {
d2014 3
a2016 3
         if ((istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+i,
                             imgcrd+wcs->lat, phi, theta, world+i,
                             world+wcs->lat, istatp))) {
d2042 1
a2042 1
         if ((iso_x = wcsutil_allEq(ncoord, nelem, imgcrd+i))) {
d2138 1
a2138 1
      if ((status = wcsset(wcs))) return status;
d2174 1
a2174 1
         if ((isolng = wcsutil_allEq(ncoord, nelem, world+i))) {
d2178 1
a2178 1
         if ((isolat = wcsutil_allEq(ncoord, nelem, world+wcs->lat))) {
d2183 3
a2185 3
         if ((istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+i,
                             world+wcs->lat, phi, theta, imgcrd+i,
                             imgcrd+wcs->lat, istatp))) {
d2246 1
a2246 1
         if ((isospec = wcsutil_allEq(ncoord, nelem, world+i))) {
d2312 1
a2312 1
   if ((istat = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd))) {
d2356 1
a2356 1
      if ((status = wcsset(wcs))) return status;
d2402 2
a2403 2
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2413 2
a2414 2
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2440 2
a2441 2
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
d2482 2
a2483 2
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
d2533 2
a2534 2
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
d2542 2
a2543 2
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
d2551 2
a2552 2
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
d2561 2
a2562 2
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
d2595 2
a2596 2
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2606 2
a2607 2
         if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2632 2
a2633 2
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
d2674 2
a2675 2
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
d2725 2
a2726 2
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
d2734 2
a2735 2
               if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                    pixcrd, stat))) {
d2743 2
a2744 2
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
d2753 2
a2754 2
                  if ((status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                       pixcrd, stat))) {
d2821 2
a2822 2
      if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                           stat))) {
d2840 2
a2841 2
         if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2873 2
a2874 2
         if ((status = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                              stat))) {
d2918 1
a2918 1
      if ((status = wcsset(wcs))) return status;
d2938 3
a2940 3
   if ((status = spctrn(wcs->ctype[j], wcs->crval[j], wcs->cdelt[j],
                        wcs->restfrq, wcs->restwav, ctype, &crval,
                        &cdelt))) {
@


4.2.1.6
log
@Cast pointers to (void *) for %p formatting by printf() to avert a compiler
warning.
@
text
@d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.5 2007/06/29 02:11:55 cal103 Exp cal103 $
d1023 1
a1023 1
   printf("      crpix: %p\n", (void *)wcs->crpix);
d1032 1
a1032 1
   printf("         pc: %p\n", (void *)wcs->pc);
d1041 1
a1041 1
   printf("      cdelt: %p\n", (void *)wcs->cdelt);
d1049 1
a1049 1
   printf("      crval: %p\n", (void *)wcs->crval);
d1057 1
a1057 1
   printf("      cunit: %p\n", (void *)wcs->cunit);
d1062 1
a1062 1
   printf("      ctype: %p\n", (void *)wcs->ctype);
d1078 3
a1080 3
   printf("        npv: %d\n", wcs->npv);
   printf("     npvmax: %d\n", wcs->npvmax);
   printf("         pv: %p\n", (void *)wcs->pv);
d1085 3
a1087 3
   printf("        nps: %d\n", wcs->nps);
   printf("     npsmax: %d\n", wcs->npsmax);
   printf("         ps: %p\n", (void *)wcs->ps);
d1097 1
a1097 1
   printf("         cd: %p\n", (void *)wcs->cd);
d1108 1
a1108 1
   printf("      crota: %p\n", (void *)wcs->crota);
d1121 1
a1121 1
   printf("      colax: %p\n", (void *)wcs->colax);
d1136 1
a1136 1
   printf("      cname: %p\n", (void *)wcs->cname);
d1147 1
a1147 1
   printf("      crder: %p\n", (void *)wcs->crder);
d1160 1
a1160 1
   printf("      csyer: %p\n", (void *)wcs->csyer);
d1250 1
a1250 1
   printf("        tab: %p", (void *)wcs->tab);
d1254 1
a1254 1
   printf("        wtb: %p", (void *)wcs->wtb);
d1259 1
a1259 1
   printf("      types: %p\n           ", (void *)wcs->types);
d1279 1
a1279 1
   printf("    m_crpix: %p", (void *)wcs->m_crpix);
d1282 1
a1282 1
   printf("       m_pc: %p", (void *)wcs->m_pc);
d1285 1
a1285 1
   printf("    m_cdelt: %p", (void *)wcs->m_cdelt);
d1288 1
a1288 1
   printf("    m_crval: %p", (void *)wcs->m_crval);
d1291 1
a1291 1
   printf("    m_cunit: %p", (void *)wcs->m_cunit);
d1294 1
a1294 1
   printf("    m_ctype: %p", (void *)wcs->m_ctype);
d1297 1
a1297 1
   printf("       m_pv: %p", (void *)wcs->m_pv);
d1300 1
a1300 1
   printf("       m_ps: %p", (void *)wcs->m_ps);
d1303 1
a1303 1
   printf("       m_cd: %p", (void *)wcs->m_cd);
d1306 1
a1306 1
   printf("    m_crota: %p", (void *)wcs->m_crota);
d1310 1
a1310 1
   printf("    m_colax: %p", (void *)wcs->m_colax);
d1312 1
a1312 1
   printf("    m_cname: %p", (void *)wcs->m_cname);
d1315 1
a1315 1
   printf("    m_crder: %p", (void *)wcs->m_crder);
d1318 1
a1318 1
   printf("    m_csyer: %p", (void *)wcs->m_csyer);
d1321 1
a1321 1
   printf("      m_tab: %p", (void *)wcs->m_tab);
d1324 1
a1324 1
   printf("      m_wtb: %p", (void *)wcs->m_wtb);
d1342 2
a1343 3
         printf("     dimlen: %p\n", (void *)wtbp->dimlen);
         printf("     arrayp: %p -> %p\n", (void *)wtbp->arrayp,
                                           (void *)(*(wtbp->arrayp)));
@


4.2.1.7
log
@In wcs_units(), always set wcsprm.cunit[i], if possible, for use by wcshdo().
@
text
@d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.6 2007/07/11 02:01:30 cal103 Exp cal103 $
a1040 1
   /* Coordinate increment at reference point. */
d1048 1
a1048 1
   /* Coordinate value at reference point. */
a1883 3

      } else {
         strcpy(wcs->cunit[i], units);
@


4.2.1.8
log
@Cosmetic change, use 0x0 for null pointers in calls to spctyp().
@
text
@d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.7 2007/07/27 04:32:14 cal103 Exp cal103 $
d1509 1
a1509 1
      spctyp(wcs->ctype[wcs->spec], stype, scode, 0x0, 0x0, 0x0, 0x0, 0x0);
d1691 1
a1691 1
         } else if (spctyp(ctypei, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
d1702 1
a1702 1
      if (spctyp(ctypei, 0x0, scode, 0x0, 0x0, 0x0, 0x0, 0x0) == 0) {
d1857 1
a1857 1
         spctyp(ctype, 0x0, 0x0, 0x0, units, 0x0, 0x0, 0x0);
d2954 1
a2954 1
   spctyp(ctype, 0x0, 0x0, 0x0, wcs->cunit[j], 0x0, 0x0, 0x0);
@


4.2.1.9
log
@Replaced use of the obsolete term "card".
@
text
@d30 1
a30 1
*   $Id: wcs.c,v 4.2.1.8 2007/07/27 08:43:10 cal103 Exp cal103 $
d54 1
a54 1
/* Maximum number of PVi_ma and PSi_ma keywords. */
d1405 1
a1405 1
      /* CRVALia, LONPOLEa, and LATPOLEa keyvalues. */
d1411 1
a1411 1
      /* PVi_ma keyvalues. */
d1417 1
a1417 1
            /* From a PROJPn keyword. */
d1440 1
a1440 1
               /* If present, overrides LONPOLEa. */
d1444 1
a1444 1
               /* If present, overrides LATPOLEa. */
d1478 1
a1478 1
      /* Update LONPOLE, LATPOLE, and PVi_ma keyvalues. */
d1513 1
a1513 1
      /* CRVALia, RESTFRQa, and RESTWAVa keyvalues. */
d1518 1
a1518 1
      /* PVi_ma keyvalues. */
d1617 1
a1617 1
   /* Parse the CTYPEia keyvalues. */
d2950 1
a2950 1
   /* Translate keyvalues. */
@


4.2.1.10
log
@Switched to LGPL 3.0.
@
text
@d2 29
a30 29
    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: wcs.c,v 4.2.1.9 2007/08/02 04:28:32 cal103 Exp cal103 $
a1312 1
   printf("\n");
@


4.1
log
@WCSLIB 4.1: major changes to implement -LOG and -TAB coordinate axes, and to
implement units conversions in wcsset(); -TAB required new members of the
wcsprm struct - ntab, tab, nwtb, wtb; also added dateavg to wcsprm; set
wcs_errmsg[0] to "success"; removed support for K&R C; moved prototypes for
vector helper functions from wcs.h; changed position of crval in the wcsprm
struct for alignment; use memset() to initialize variables an wcsini(),
default value of lonpole is UNDEFINED, latpole is +90.0 (were 999.0); report
values to an extra decimal place in wcsprt(), and report all memory
management members; overhauled wcsset() to support -LOG and -TAB, making it
more general and splitting some of its functionality into new helper
functions wcs_types(), which uses new member wcsprm.types, and wcs_units()
that does units conversions based on cunit; wcsset() recognizes AIPS
spectral types, via wcs_types() and spctyp(); wcsset() resets lonpole and
latpole to the values actually used, and null-fills all string members
(mainly to prevent gdb printing garbage); new utility function wcssptr()
translates the spectral axis in a wcsprm struct.
@
text
@d3 1
a3 1
*   WCSLIB 4.1 - an implementation of the FITS WCS standard.
d30 1
a30 1
*   $Id: wcs.c,v 4.0 2005/02/04 06:08:26 cal103 Exp cal103 $
a80 4
int  wcs_allEq(int, int, const double *);
void wcs_setAll(int, int, double *);
void wcs_setAli(int, int, int *);

a92 1
   size_t elsize;
d227 1
a227 2
            elsize = sizeof(char [72]);
            if (!(wcs->cunit = (char (*)[72])calloc(naxis, elsize))) {
d244 1
a244 2
            elsize = sizeof(char [72]);
            if (!(wcs->ctype = (char (*)[72])calloc(naxis, elsize))) {
d262 1
a262 2
               elsize = sizeof(struct pvcard);
               if (!(wcs->pv = (struct pvcard *)calloc(NPVMAX, elsize))) {
d285 1
a285 2
              elsize = sizeof(struct pscard);
              if (!(wcs->ps = (struct pscard *)calloc(NPSMAX, elsize))) {
d341 1
a341 2
            elsize = sizeof(char [72]);
            if (!(wcs->cname = (char (*)[72])calloc(naxis, elsize))) {
d986 1
d1219 3
a1221 1
   printf("        wtb: 0x%x\n", (int)wcs->wtb);
d1291 19
d1825 5
d1866 2
a1867 1
   int    face, i, iso_x, iso_y, istat, itab, k, nx, ny, *statp, status, type;
d1888 8
d1926 1
d1930 1
a1930 1
                  *statp = 1;
d1932 1
d1934 2
d1955 1
a1955 1
                     *statp = 1;
d1968 1
a1968 1
         if (iso_x = wcs_allEq(ncoord, nelem, imgcrd+i)) {
d1972 1
a1972 1
         if (iso_y = wcs_allEq(ncoord, nelem, imgcrd+wcs->lat)) {
d1979 1
a1979 1
                            world+wcs->lat, stat)) {
d1983 2
a1984 1
               return istat + 3;
d1990 10
a1999 5
            wcs_setAll(ncoord, nelem, world+i);
            wcs_setAll(ncoord, nelem, world+wcs->lat);
            wcs_setAll(ncoord, 1, phi);
            wcs_setAll(ncoord, 1, theta);
            wcs_setAli(ncoord, 1, stat);
d2005 1
a2005 1
         if (iso_x = wcs_allEq(ncoord, nelem, imgcrd+i)) {
d2013 1
a2013 1
                           stat);
d2018 1
a2018 1
                           stat);
d2025 2
a2026 1
               return istat + 3;
d2032 6
a2037 2
            wcs_setAll(ncoord, nelem, world+i);
            wcs_setAli(ncoord, 1, stat);
d2045 1
a2045 1
      istat = tabx2s(wcs->tab + itab, ncoord, nelem, imgcrd, world, stat);
d2049 10
a2058 2
      } else {
         return (istat == 3) ? 5 : istat;
d2066 1
a2066 1
      wcs_setAll(ncoord, nelem, world+i);
d2069 2
d2088 2
a2089 2
   int    i, isolat, isolng, isospec, istat, itab, k, nlat, nlng, nwrld,
          status, type;
d2107 8
d2137 1
a2137 1
         if (isolng = wcs_allEq(ncoord, nelem, world+i)) {
d2141 1
a2141 1
         if (isolat = wcs_allEq(ncoord, nelem, world+wcs->lat)) {
d2148 1
a2148 1
                            imgcrd+wcs->lat, stat)) {
d2152 2
a2153 1
               return istat + 3;
d2159 10
a2168 5
            wcs_setAll(ncoord, nelem, imgcrd+i);
            wcs_setAll(ncoord, nelem, imgcrd+wcs->lat);
            wcs_setAll(ncoord, 1, phi);
            wcs_setAll(ncoord, 1, theta);
            wcs_setAli(ncoord, 1, stat);
d2209 1
a2209 1
         if (isospec = wcs_allEq(ncoord, nelem, world+i)) {
d2217 1
a2217 1
                           imgcrd+i, stat);
d2222 1
a2222 1
                           imgcrd+i, stat);
d2229 2
a2230 1
               return istat + 3;
d2236 6
a2241 2
            wcs_setAll(ncoord, nelem, imgcrd+i);
            wcs_setAli(ncoord, 1, stat);
d2249 1
a2249 1
      istat = tabs2x(wcs->tab + itab, ncoord, nelem, world, imgcrd, stat);
d2253 10
a2262 2
      } else {
         return (istat == 3) ? 5 : istat;
d2270 1
a2270 1
      wcs_setAll(ncoord, nelem, imgcrd+i);
d2276 2
a2277 1
      return istat;
d2280 2
a2929 42
}

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

int wcs_allEq(int ncoord, int nelem, const double *first)

{
   double v0;
   const double *vp;

   v0 = *first;
   for (vp = first+nelem; vp < first + ncoord*nelem; vp += nelem) {
     if (*vp != v0) return 0;
   }

   return 1;
}

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

void wcs_setAll(int ncoord, int nelem, double *first)

{
   double v0, *vp;

   v0 = *first;
   for (vp = first+nelem; vp < first + ncoord*nelem; vp += nelem) {
     *vp = v0;
   }
}

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

void wcs_setAli(int ncoord, int nelem, int *first)

{
   int v0, *vp;

   v0 = *first;
   for (vp = first+nelem; vp < first + ncoord*nelem; vp += nelem) {
     *vp = v0;
   }
@


4.0
log
@WCSLIB 4.0: changed from LGPL to GPL; do basic sanity checks on the values
given for ncoord and nelem in wcsp2s() and wcss2p(); macros for UNDEFINED
values moved to wcsmath.h; removed unnecessary casts of void pointers (a
hangover from K&R C).
@
text
@d3 1
a3 1
*   WCSLIB 4.0 - an implementation of the FITS WCS standard.
d30 1
a30 1
*   $Id: wcs.c,v 3.6 2004/08/25 05:18:22 cal103 Exp cal103 $
d40 7
d48 2
d60 1
a60 1
   0,
d77 8
d87 2
a88 18
int wcsnpv(npvmax)

int npvmax;

{
   if (npvmax >= 0) NPVMAX = npvmax;
   return NPVMAX;
}


int wcsnps(npsmax)

int npsmax;

{
   if (npsmax >= 0) NPSMAX = npsmax;
   return NPSMAX;
}
d92 1
a92 4
int wcsini(alloc, naxis, wcs)

int alloc, naxis;
struct wcsprm *wcs;
d99 1
a99 1
   if (wcs == 0) return 1;
d109 19
a127 13
      wcs->m_crpix = 0;
      wcs->m_pc    = 0;
      wcs->m_cdelt = 0;
      wcs->m_cunit = 0;
      wcs->m_ctype = 0;
      wcs->m_crval = 0;
      wcs->m_pv    = 0;
      wcs->m_ps    = 0;
      wcs->m_cd    = 0;
      wcs->m_crota = 0;
      wcs->m_cname = 0;
      wcs->m_crder = 0;
      wcs->m_csyer = 0;
d130 1
a130 3
   if (wcs->flag == -1) {
      wcs->lin.flag = -1;
   }
d135 13
a147 13
       wcs->crpix == 0 ||
       wcs->pc    == 0 ||
       wcs->cdelt == 0 ||
       wcs->cunit == 0 ||
       wcs->ctype == 0 ||
       wcs->crval == 0 ||
       (NPVMAX && wcs->pv == 0) ||
       (NPSMAX && wcs->ps == 0) ||
       wcs->cd    == 0 ||
       wcs->crota == 0 ||
       wcs->cname == 0 ||
       wcs->crder == 0 ||
       wcs->csyer == 0) {
d159 1
a159 1
      if (alloc || wcs->crpix == 0) {
d175 1
a175 1
      if (alloc || wcs->pc == 0) {
d192 1
a192 1
      if (alloc || wcs->cdelt == 0) {
d209 2
a210 2
      if (alloc || wcs->cunit == 0) {
         if (wcs->m_cunit) {
d212 1
a212 1
            wcs->cunit = wcs->m_cunit;
d215 1
a215 2
            elsize = sizeof(char [72]);
            if (!(wcs->cunit = (char (*)[72])calloc(naxis, elsize))) {
d222 1
a222 1
            wcs->m_cunit = wcs->cunit;
d226 2
a227 2
      if (alloc || wcs->ctype == 0) {
         if (wcs->m_ctype) {
d229 1
a229 1
            wcs->ctype = wcs->m_ctype;
d233 1
a233 1
            if (!(wcs->ctype = (char (*)[72])calloc(naxis, elsize))) {
d240 1
a240 1
            wcs->m_ctype = wcs->ctype;
d244 2
a245 2
      if (alloc || wcs->crval == 0) {
         if (wcs->m_crval) {
d247 1
a247 1
            wcs->crval = wcs->m_crval;
d250 2
a251 1
            if (!(wcs->crval = calloc(naxis, sizeof(double)))) {
d258 1
a258 1
            wcs->m_crval = wcs->crval;
d262 1
a262 1
      if (alloc || wcs->pv == 0) {
d269 5
a273 5
              elsize = sizeof(struct pvcard);
              if (!(wcs->pv = (struct pvcard *)calloc(NPVMAX, elsize))) {
                 wcsfree(wcs);
                 return 2;
              }
d275 1
a275 1
              wcs->pv = (struct pvcard *)0;
d286 1
a286 1
      if (alloc || wcs->ps == 0) {
d310 1
a310 1
      if (alloc || wcs->cd == 0) {
d327 1
a327 1
      if (alloc || wcs->crota == 0) {
d344 1
a344 1
      if (alloc || wcs->cname == 0) {
d362 1
a362 1
      if (alloc || wcs->crder == 0) {
d379 1
a379 1
      if (alloc || wcs->csyer == 0) {
d412 1
a412 1
   /* CUNITia and CTYPEia are blank by default. */
d414 1
a414 2
      wcs->cunit[i][0] = '\0';
      wcs->ctype[i][0] = '\0';
d418 1
a418 1
   /* CRVALia defaults to 0.0. */
d420 2
a421 1
      wcs->crval[i] = 0.0;
d426 2
a427 2
   wcs->lonpole = 999.0;
   wcs->latpole = 999.0;
d430 2
a431 2
   wcs->restfrq = 0.0;
   wcs->restwav = 0.0;
d445 1
a445 1
     wcs->ps[k].value[0] = '\0';
d461 1
d464 1
a464 1
   wcs->wcsname[0] = '\0';
d466 1
a466 1
      wcs->cname[i][0] = '\0';
d470 1
a470 1
   wcs->radesys[0] = '\0';
d472 2
a473 2
   wcs->specsys[0] = '\0';
   wcs->ssysobs[0] = '\0';
d475 1
a475 1
   wcs->ssyssrc[0] = '\0';
d480 2
a481 1
   wcs->dateobs[0] = '\0';
d485 5
d506 6
a511 6
int wcssub(alloc, wcssrc, nsub, axes, wcsdst)

int alloc;
const struct wcsprm *wcssrc;
int *nsub, axes[];
struct wcsprm *wcsdst;
d515 2
a516 2
   int  axis, cubeface, dealloc, dummy, i, j, k, latitude, longitude,
        *map = 0, msub, naxis, npv, nps, other, spectral, status, stokes;
d519 1
d521 1
a521 1
   if (wcssrc == 0) return 1;
d531 1
a531 1
   if (nsub == 0) {
d538 1
a538 1
   if (dealloc = (axes == 0)) {
d541 1
d656 1
a656 1
         goto dealloc;
d662 1
a662 1
      goto dealloc;
d688 1
a688 1
               goto dealloc;
d721 1
a721 1
      goto dealloc;
d749 3
a751 1
   /* Coordinate units and type. */
d754 1
a754 2
      strncpy(wcsdst->cunit[i], wcssrc->cunit[k], 72);
      strncpy(wcsdst->ctype[i], wcssrc->ctype[k], 72);
d757 1
a757 3
   /* Coordinate reference value. */
   srcp = wcssrc->crval;
   dstp = wcsdst->crval;
d760 2
a761 1
      *(dstp++) = *(srcp+k);
d774 1
a774 1
      if (i == 0 || (i > 0 && (i = map[i-1]))) {
d777 1
a777 1
         wcsdst->pv[npv].i = i;
d786 1
a786 1
      if (i > 0 && (i = map[i-1])) {
d788 1
a788 1
         wcsdst->ps[nps].i = i;
d839 1
d844 44
a887 1
dealloc:
d893 2
d900 1
a900 1
int wcsfree(wcs)
d902 2
a903 1
struct wcsprm *wcs;
d905 1
a905 2
{
   if (wcs == 0) return 1;
d913 71
a983 49
         if (wcs->crpix == wcs->m_crpix) wcs->crpix = 0;
         if (wcs->pc    == wcs->m_pc)    wcs->pc    = 0;
         if (wcs->cdelt == wcs->m_cdelt) wcs->cdelt = 0;
         if (wcs->cunit == wcs->m_cunit) wcs->cunit = 0;
         if (wcs->ctype == wcs->m_ctype) wcs->ctype = 0;
         if (wcs->crval == wcs->m_crval) wcs->crval = 0;
         if (wcs->pv    == wcs->m_pv)    wcs->pv    = 0;
         if (wcs->ps    == wcs->m_ps)    wcs->ps    = 0;
         if (wcs->cd    == wcs->m_cd)    wcs->cd    = 0;
         if (wcs->crota == wcs->m_crota) wcs->crota = 0;
         if (wcs->cname == wcs->m_cname) wcs->cname = 0;
         if (wcs->crder == wcs->m_crder) wcs->crder = 0;
         if (wcs->csyer == wcs->m_csyer) wcs->csyer = 0;

         if (wcs->m_crpix) free(wcs->m_crpix);
         if (wcs->m_pc)    free(wcs->m_pc);
         if (wcs->m_cdelt) free(wcs->m_cdelt);
         if (wcs->m_cunit) free(wcs->m_cunit);
         if (wcs->m_ctype) free(wcs->m_ctype);
         if (wcs->m_crval) free(wcs->m_crval);
         if (wcs->m_pv)    free(wcs->m_pv);
         if (wcs->m_ps)    free(wcs->m_ps);
         if (wcs->m_cd)    free(wcs->m_cd);
         if (wcs->m_crota) free(wcs->m_crota);
         if (wcs->m_cname) free(wcs->m_cname);
         if (wcs->m_crder) free(wcs->m_crder);
         if (wcs->m_csyer) free(wcs->m_csyer);
      }

      if (wcs->lin.crpix == wcs->m_crpix) wcs->lin.crpix = 0;
      if (wcs->lin.pc    == wcs->m_pc)    wcs->lin.pc    = 0;
      if (wcs->lin.cdelt == wcs->m_cdelt) wcs->lin.cdelt = 0;
   }

   wcs->m_flag  = 0;
   wcs->m_naxis = 0;
   wcs->m_crpix = 0;
   wcs->m_pc    = 0;
   wcs->m_cdelt = 0;
   wcs->m_cunit = 0;
   wcs->m_ctype = 0;
   wcs->m_crval = 0;
   wcs->m_pv    = 0;
   wcs->m_ps    = 0;
   wcs->m_cd    = 0;
   wcs->m_crota = 0;
   wcs->m_cname = 0;
   wcs->m_crder = 0;
   wcs->m_csyer = 0;
d992 1
a992 3
int wcsprt(wcs)

const struct wcsprm *wcs;
d997 1
a997 1
   if (wcs == 0) return 1;
d1009 1
a1009 1
      printf("  %- 11.4g", wcs->crpix[i]);
d1019 1
a1019 1
         printf("  %- 11.4g", wcs->pc[k++]);
d1027 9
a1035 1
      printf("  %- 11.4g", wcs->cdelt[i]);
d1050 5
a1054 5
   /* Coordinate reference value. */
   printf("      crval: 0x%x\n", (int)wcs->crval);
   printf("            ");
   for (i = 0; i < wcs->naxis; i++) {
      printf("  %- 11.4g", wcs->crval[i]);
a1055 4
   printf("\n");

   /* Celestial and spectral transformation parameters. */
   printf("    lonpole: %9f\n", wcs->lonpole);
d1065 1
a1065 1
      printf("             %3d%4d  %- 11.4g\n", (wcs->pv[i]).i,
d1085 1
a1085 1
            printf("  %- 11.4g", wcs->cd[k++]);
d1095 1
a1095 1
         printf("  %- 11.4g", wcs->crota[i]);
d1128 1
a1128 1
            printf("  %- 11.4g", wcs->crder[i]);
d1141 1
a1141 1
            printf("  %- 11.4g", wcs->csyer[i]);
d1194 1
a1194 1
         printf("%- 11.4g  ", wcs->obsgeo[i]);
d1205 6
d1223 7
d1231 6
d1275 30
d1326 1
a1326 3
int wcsset(wcs)

struct wcsprm *wcs;
d1329 2
a1330 5
   const int  nalias = 2;
   const char aliases [2][4] = {"NCP", "GLS"};

   char ctypei[72], pcode[4], requir[9];
   int i, j, k, m, naxis, *ndx = 0, status;
d1338 4
a1341 116
   if (wcs == 0) return 1;

   /* Parse the CTYPEia cards. */
   pcode[0] = '\0';
   requir[0] = '\0';
   wcs->lng  = -1;
   wcs->lat  = -1;
   wcs->spec = -1;
   wcs->cubeface = -1;

   naxis = wcs->naxis;
   for (i = 0; i < naxis; i++) {
      strncpy(ctypei, wcs->ctype[i], 72);
      ctypei[71] = '\0';

      if (ctypei[4] != '-') {
         if (strcmp(ctypei, "CUBEFACE") == 0) {
            if (wcs->cubeface == -1) {
               wcs->cubeface = i;
            } else {
               /* Multiple CUBEFACE axes! */
               return 4;
            }
         }
         continue;
      }


      /* Got an axis qualifier, is it a recognized spectral type? */
      for (k = 0; k < spc_ncode; k++) {
         if (strncmp(ctypei+5, spc_codes[k], 3) == 0) {
            /* Parse the spectral axis type. */
            wcs->spec = i;
            break;
         }
      }

      if (k < spc_ncode) {
         continue;
      }


      /* Is it a recognized celestial projection? */
      for (k = 0; k < prj_ncode; k++) {
         if (strncmp(ctypei+5, prj_codes[k], 3) == 0) break;
      }

      if (k == prj_ncode) {
         /* Maybe it's a projection alias. */
         for (k = 0; k < nalias; k++) {
            if (strncmp(ctypei+5, aliases[k], 3) == 0) break;
         }

         if (k == nalias) {
            /* Not recognized. */
            continue;
         }
      }

      /* Parse the celestial axis type. */
      if (strcmp(pcode, "") == 0) {
         sprintf(pcode, "%.3s", ctypei+5);

         if (strncmp(ctypei, "RA--", 4) == 0) {
            wcs->lng = i;
            strcpy(wcs->lngtyp, "RA");
            strcpy(wcs->lattyp, "DEC");
            ndx = &wcs->lat;
            sprintf(requir, "DEC--%s", pcode);
         } else if (strncmp(ctypei, "DEC-", 4) == 0) {
            wcs->lat = i;
            strcpy(wcs->lngtyp, "RA");
            strcpy(wcs->lattyp, "DEC");
            ndx = &wcs->lng;
            sprintf(requir, "RA---%s", pcode);
         } else if (strncmp(ctypei+1, "LON", 3) == 0) {
            wcs->lng = i;
            sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
            sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
            ndx = &wcs->lat;
            sprintf(requir, "%s-%s", wcs->lattyp, pcode);
         } else if (strncmp(ctypei+1, "LAT", 3) == 0) {
            wcs->lat = i;
            sprintf(wcs->lngtyp, "%cLON", ctypei[0]);
            sprintf(wcs->lattyp, "%cLAT", ctypei[0]);
            ndx = &wcs->lng;
            sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
         } else if (strncmp(ctypei+2, "LN", 2) == 0) {
            wcs->lng = i;
            sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
            sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
            ndx = &wcs->lat;
            sprintf(requir, "%s-%s", wcs->lattyp, pcode);
         } else if (strncmp(ctypei+2, "LT", 2) == 0) {
            wcs->lat = i;
            sprintf(wcs->lngtyp, "%c%cLN", ctypei[0], ctypei[1]);
            sprintf(wcs->lattyp, "%c%cLT", ctypei[0], ctypei[1]);
            ndx = &wcs->lng;
            sprintf(requir, "%s-%s", wcs->lngtyp, pcode);
         } else {
            /* Unrecognized celestial type. */
            wcs->lng = -1;
            wcs->lat = -1;
            return 4;
         }
      } else {
         if (strncmp(ctypei, requir, 8) != 0) {
            /* Inconsistent projection types. */
            wcs->lng = -1;
            wcs->lat = -1;
            return 4;
         }

         *ndx = i;
         requir[0] = '\0';
      }
d1344 3
a1346 6

   if (strcmp(requir, "")) {
      /* Unmatched celestial axis. */
      wcs->lng = -1;
      wcs->lat = -1;
      return 4;
d1350 2
a1351 2
   /* Celestial projection present? */
   if (wcs->lng >= 0) {
d1404 1
a1404 1
      if (strncmp(pcode, "GLS", 3) == 0) {
d1407 1
a1407 1
      } else if (strcmp(pcode, "NCP") == 0) {
d1418 1
a1418 1
         strcpy(wcsprj->code, pcode);
a1425 1
   }
d1427 3
d1431 37
a1467 13
   /* Spectral axis present? */
   if (wcs->spec >= 0) {
      spcini(wcsspc);

      sprintf(wcsspc->type, "%.4s", wcs->ctype[wcs->spec]);
      sprintf(wcsspc->code, "%.3s", wcs->ctype[wcs->spec]+5);

      /* CRVALia, RESTFRQa, and RESTWAVa cards. */
      wcsspc->crval = wcs->crval[wcs->spec];
      wcsspc->restfrq = wcs->restfrq;
      wcsspc->restwav = wcs->restwav;

      /* PVi_ma cards. */
d1487 8
d1496 1
d1534 14
d1553 282
d1837 10
a1846 9
int wcsp2s(wcs, ncoord, nelem, pixcrd, imgcrd, phi, theta, world, stat)

struct wcsprm *wcs;
int ncoord, nelem;
const double pixcrd[];
double imgcrd[];
double phi[], theta[];
double world[];
int stat[];
d1849 2
a1850 3
   int    face, i, iso_x, iso_y, istat, k, nx, ny, *statp, status, wcslat,
          wcslng, wcspec;
   double offset, *worldlat, *worldlng;
d1853 1
d1856 1
a1856 1
   if (wcs == 0) return 1;
a1869 3
   wcslng = wcs->lng;
   wcslat = wcs->lat;
   wcspec = wcs->spec;
d1871 25
d1897 32
a1928 8
   /* Convert intermediate world coordinates to world coordinates. */
   img = imgcrd;
   wrl = world;
   for (k = 0; k < ncoord; k++) {
      for (i = 0; i < wcs->naxis; i++, img++, wrl++) {
         if (i == wcslng || i == wcslat || i == wcspec) continue;
         *wrl = *img + wcs->crval[i];
      }
d1930 3
a1932 4
      /* Zero the unused world coordinate elements. */
      for (i = wcs->naxis; i < nelem; i++) {
         *(wrl++) = 0.0;
      }
d1934 3
a1936 2
      img += (nelem - wcs->naxis);
   }
d1938 6
a1943 9
   /* Convert celestial coordinates. */
   if (wcs->lng >= 0) {
      /* Do we have a CUBEFACE axis? */
      if (wcs->cubeface != -1) {
         /* Separation between faces. */
         if (wcscel->prj.r0 == 0.0) {
            offset = 90.0;
         } else {
            offset = wcscel->prj.r0*PI/2.0;
d1946 5
a1950 7
         /* Lay out faces in a plane. */
         img = imgcrd;
         statp = stat;
         for (k = 0; k < ncoord; k++, statp++) {
            face = (int)(*(img+wcs->cubeface) + 0.5);
            if (fabs(*(img+wcs->cubeface) - face) > 1e-10) {
               *statp = 1;
d1953 1
a1953 22
               switch (face) {
               case 0:
                  *(img+wcslat) += offset;
                  break;
               case 1:
                  break;
               case 2:
                  *(img+wcslng) += offset;
                  break;
               case 3:
                  *(img+wcslng) += offset*2;
                  break;
               case 4:
                  *(img+wcslng) += offset*3;
                  break;
               case 5:
                  *(img+wcslat) -= offset;
                  break;
               default:
                  *statp = 1;
                  status = 8;
               }
d1955 10
d1966 5
a1970 1
            img += nelem;
a1971 1
      }
d1973 5
d1979 12
a1990 22
      /* Check for constant x and/or y. */
      nx = ncoord;
      ny = 0;

      if (iso_x = wcs_allEq(ncoord, nelem, imgcrd+wcslng)) {
         nx = 1;
         ny = ncoord;
      }
      if (iso_y = wcs_allEq(ncoord, nelem, imgcrd+wcslat)) {
         ny = 1;
      }

      /* Transform projection plane coordinates to celestial coordinates. */
      worldlng = world + wcslng;
      worldlat = world + wcslat;
      if (istat = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+wcslng,
                         imgcrd+wcslat, phi, theta, worldlng, worldlat,
                         stat)) {;
         if (istat == 5) {
            status = 8;
         } else {
            return istat + 3;
a1991 1
      }
d1993 5
a1997 7
      /* If x and y were both constant, replicate values. */
      if (iso_x && iso_y) {
         wcs_setAll(ncoord, nelem, worldlng);
         wcs_setAll(ncoord, nelem, worldlat);
         wcs_setAll(ncoord, 1, phi);
         wcs_setAll(ncoord, 1, theta);
         wcs_setAli(ncoord, 1, stat);
d2002 8
a2009 6
   /* Convert spectral coordinates. */
   if (wcs->spec >= 0) {
      /* Check for constant x. */
      nx = ncoord;
      if (iso_x = wcs_allEq(ncoord, nelem, imgcrd+wcspec)) {
         nx = 1;
d2011 1
a2012 8
      if (istat = spcx2s(&(wcs->spc), nx, nelem, nelem, imgcrd+wcspec,
                         world+wcspec, stat)) {
         if (istat == 3) {
            status = 8;
         } else {
            return istat + 3;
         }
      }
d2014 4
a2017 5
      /* If x was constant, replicate values. */
      if (iso_x) {
         wcs_setAll(ncoord, nelem, world+wcspec);
         wcs_setAli(ncoord, 1, stat);
      }
d2025 10
a2034 9
int wcss2p(wcs, ncoord, nelem, world, phi, theta, imgcrd, pixcrd, stat)

struct wcsprm* wcs;
int ncoord, nelem;
const double world[];
double phi[], theta[];
double imgcrd[];
double pixcrd[];
int stat[];
d2037 3
a2039 3
   int    i, isolat, isolng, isospec, istat, k, nlat, nlng, nspec, status,
          wcslat, wcslng, wcspec;
   double offset;
d2043 1
d2048 1
a2048 1
   if (wcs == 0) return 1;
a2055 4
   wcslng = wcs->lng;
   wcslat = wcs->lat;
   wcspec = wcs->spec;

d2058 3
a2060 2
   wrl = world;
   img = imgcrd;
d2062 10
a2071 5
   for (k = 0; k < ncoord; k++) {
      for (i = 0; i < wcs->naxis; i++, wrl++, img++) {
         if (i == wcslng || i == wcslat || i == wcspec) continue;
         *img = *wrl - wcs->crval[i];
      }
d2073 23
a2095 22
      /* Zero the unused intermediate world coordinate elements. */
      for (i = wcs->naxis; i < nelem; i++) {
         *(img++) = 0.0;
      }

      wrl += (nelem - wcs->naxis);
   }


   /* Celestial coordinates. */
   if (wcs->lng >= 0) {
      /* Check for constant lng and/or lat. */
      nlng = ncoord;
      nlat = 0;

      if (isolng = wcs_allEq(ncoord, nelem, world+wcslng)) {
         nlng = 1;
         nlat = ncoord;
      }
      if (isolat = wcs_allEq(ncoord, nelem, world+wcslat)) {
         nlat = 1;
      }
d2097 7
a2103 8
      /* Transform celestial coordinates to projection plane coordinates. */
      if (istat = cels2x(wcscel, nlng, nlat, nelem, nelem, world+wcslng,
                         world+wcslat, phi, theta, imgcrd+wcslng,
                         imgcrd+wcslat, stat)) {
         if (istat == 6) {
            status = 9;
         } else {
            return istat + 3;
a2104 1
      }
d2106 8
a2113 8
      /* If lng and lat were both constant, replicate values. */
      if (isolng && isolat) {
         wcs_setAll(ncoord, nelem, imgcrd+wcslng);
         wcs_setAll(ncoord, nelem, imgcrd+wcslat);
         wcs_setAll(ncoord, 1, phi);
         wcs_setAll(ncoord, 1, theta);
         wcs_setAli(ncoord, 1, stat);
      }
d2115 24
a2138 7
      /* Do we have a CUBEFACE axis? */
      if (wcs->cubeface != -1) {
         /* Separation between faces. */
         if (wcscel->prj.r0 == 0.0) {
            offset = 90.0;
         } else {
            offset = wcscel->prj.r0*PI/2.0;
d2141 22
a2162 18
         /* Stack faces in a cube. */
         img = imgcrd;
         for (k = 0; k < ncoord; k++) {
            if (*(img+wcslat) < -0.5*offset) {
               *(img+wcslat) += offset;
               *(img+wcs->cubeface) = 5.0;
            } else if (*(img+wcslat) > 0.5*offset) {
               *(img+wcslat) -= offset;
               *(img+wcs->cubeface) = 0.0;
            } else if (*(img+wcslng) > 2.5*offset) {
               *(img+wcslng) -= 3.0*offset;
               *(img+wcs->cubeface) = 4.0;
            } else if (*(img+wcslng) > 1.5*offset) {
               *(img+wcslng) -= 2.0*offset;
               *(img+wcs->cubeface) = 3.0;
            } else if (*(img+wcslng) > 0.5*offset) {
               *(img+wcslng) -= offset;
               *(img+wcs->cubeface) = 2.0;
d2164 1
a2164 1
               *(img+wcs->cubeface) = 1.0;
d2166 1
d2168 4
a2171 1
            img += nelem;
d2177 8
a2184 6
   /* Spectral coordinates. */
   if (wcs->spec >= 0) {
      /* Check for constant spec. */
      nspec = ncoord;
      if (isospec = wcs_allEq(ncoord, nelem, world+wcspec)) {
         nspec = 1;
d2186 1
a2187 8
      if (istat = spcs2x(&(wcs->spc), nspec, nelem, nelem, world+wcspec,
                         imgcrd+wcspec, stat)) {
         if (istat == 4) {
            status = 9;
         } else {
            return istat + 3;
         }
      }
d2189 4
a2192 5
      /* If spec was constant, replicate values. */
      if (isospec) {
         wcs_setAll(ncoord, nelem, imgcrd+wcspec);
         wcs_setAli(ncoord, 1, stat);
      }
d2206 12
a2217 12
int wcsmix(wcs, mixpix, mixcel, vspan, vstep, viter, world, phi, theta,
           imgcrd, pixcrd)

struct wcsprm *wcs;
int mixpix, mixcel;
const double vspan[2];
double vstep;
int viter;
double world[];
double phi[], theta[];
double imgcrd[];
double pixcrd[];
d2232 1
d2236 1
a2236 1
   if (wcs == 0) return 1;
d2680 1
a2680 1
      status = sphx2s(wcs->cel.euler, 1, 1, 1, 1, phi, theta, &lng, &lat);
d2787 4
a2790 1
int wcs_allEq(ncoord, nelem, first)
d2792 62
a2853 2
int ncoord, nelem;
const double *first;
d2869 1
a2869 4
void wcs_setAll(ncoord, nelem, first)

int ncoord, nelem;
double *first;
d2882 1
a2882 4
void wcs_setAli(ncoord, nelem, first)

int ncoord, nelem;
int *first;
@


3.6
log
@WCSLIB 3.6:

   1) Added new service routine wcssub() and removed wcscopy() which is defined
      as a preprocessor macro that invokes it.

   2) Removed vsource from the wcsprm struct and added ssyssrc; modified
      wcsini() and wcsprt() to suit.

   3) In wcsini(), fixed a problem with memory management for wcs.pv when
      NPVMAX is zero likewise for wcs.ps and NPSMAX.

   4) In wcsprt(), don't print auxiliary coordinate system information in
      arrays with zero address.

   5) In wcss2p(), status == 9 (one or more invalid world coordinates) was not
      returned appropriately.

   6) "Error status/code/number" is now referred to consistently as the "status
      return value".

   7) Replaced "error" with "failed" in status messages.

   8) Removed support for K&R C.
@
text
@d3 2
a4 2
*   WCSLIB 3.6 - an implementation of the FITS WCS convention.
*   Copyright (C) 1995-2004, Mark Calabretta
d6 4
a9 4
*   This library is free software; you can redistribute it and/or modify it
*   under the terms of the GNU Library General Public License as published
*   by the Free Software Foundation; either version 2 of the License, or (at
*   your option) any later version.
d11 4
a14 4
*   This library 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 Library
*   General Public License for more details.
d16 3
a18 3
*   You should have received a copy of the GNU Library General Public License
*   along with this library; if not, write to the Free Software Foundation,
*   Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
d30 1
a30 1
*   $Id: wcs.c,v 3.5 2004/06/28 04:03:12 mcalabre Exp mcalabre $
a65 3
#define UNDEFINED 987654321.0e99
#define undefined(value) (value == UNDEFINED)

d107 1
d157 1
a157 1
      if (alloc || wcs->crpix == (double *)0) {
d163 1
a163 1
            if (!(wcs->crpix = (double *)calloc(naxis, sizeof(double)))) {
d173 1
a173 1
      if (alloc || wcs->pc == (double *)0) {
d179 1
a179 1
            if (!(wcs->pc = (double *)calloc(naxis*naxis, sizeof(double)))) {
d190 1
a190 1
      if (alloc || wcs->cdelt == (double *)0) {
d196 1
a196 1
            if (!(wcs->cdelt = (double *)calloc(naxis, sizeof(double)))) {
d207 1
a207 1
      if (alloc || wcs->cunit == (char (*)[72])0) {
d225 1
a225 1
      if (alloc || wcs->ctype == (char (*)[72])0) {
d243 1
a243 1
      if (alloc || wcs->crval == (double *)0) {
d249 1
a249 1
            if (!(wcs->crval = (double *)calloc(naxis, sizeof(double)))) {
d260 1
a260 1
      if (alloc || wcs->pv == (struct pvcard *)0) {
d284 1
a284 1
      if (alloc || wcs->ps == (struct pscard *)0) {
d308 1
a308 1
      if (alloc || wcs->cd == (double *)0) {
d314 1
a314 1
            if (!(wcs->cd = (double *)calloc(naxis*naxis, sizeof(double)))) {
d325 1
a325 1
      if (alloc || wcs->crota == (double *)0) {
d331 1
a331 1
            if (!(wcs->crota = (double *)calloc(naxis, sizeof(double)))) {
d342 1
a342 1
      if (alloc || wcs->cname == (char (*)[72])0) {
d360 1
a360 1
      if (alloc || wcs->crder == (double *)0) {
d366 1
a366 1
            if (!(wcs->crder = (double *)calloc(naxis, sizeof(double)))) {
d377 1
a377 1
      if (alloc || wcs->csyer == (double *)0) {
d383 1
a383 1
            if (!(wcs->csyer = (double *)calloc(naxis, sizeof(double)))) {
d517 1
a517 1
   if (!(map = (int *)calloc(naxis, sizeof(int)))) {
d530 1
a530 1
      if (!(axes = (int *)calloc(naxis, sizeof(int)))) {
d1519 3
d1534 2
a1535 2
   img = (double *)imgcrd;
   wrl = (double *)world;
d1562 2
a1563 2
         img = (double *)imgcrd;
         statp = (int *)stat;
d1612 2
a1613 2
      worldlng = (double *)world + wcslng;
      worldlat = (double *)world + wcslat;
d1678 2
a1679 1
   register double *img, *wrl;
d1690 3
d1699 2
a1700 2
   wrl = (double *)world;
   img = (double *)imgcrd;
d1761 1
a1761 1
         img = (double *)imgcrd;
d2130 2
a2131 2
               if (status = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                   stat)) {
@


3.5
log
@WCSLIB 3.5: use calloc() in place of malloc() in allocating memory for
arrays, and replace malloc.h with stdlib.h for all platforms; in wcsfree(),
check that wcs.flag != -1 before testing wcs.m_flag when freeing memory
allocated by wcsini(); NPVMAX, previously a C-preprocessor macro, is now a
global variable that may be set by a new function, wcsnpv(); support
auxiliary FITS WCS header cards in the wcsprm struct in wcsini(), wcscopy(),
wcsfree(), and wcsprt(); recognise i = 0 in the pvcard struct to mean the
latitude axis; changed the way altlin is handled so that bit 0 is not
cleared; added the alternate version code to FITS WCS keywords mentioned in
comments.
@
text
@d3 1
a3 1
*   WCSLIB 3.5 - an implementation of the FITS WCS convention.
d30 1
a30 1
*   $Id: wcs.c,v 3.4 2004/02/11 00:15:03 mcalabre Exp mcalabre $
d49 1
a49 1
/* Map error number to error message for each function. */
d53 1
a53 1
   "Memory allocation error",
d62 3
a64 1
   "No solution found in the specified interval"};
d274 2
d298 2
d470 1
a470 1
   wcs->equinox = UNDEFINED;
d473 6
a478 6
   wcs->velosys = UNDEFINED;
   wcs->vsource = UNDEFINED;
   wcs->zsource = UNDEFINED;
   wcs->obsgeo[0] = UNDEFINED;
   wcs->obsgeo[1] = UNDEFINED;
   wcs->obsgeo[2] = UNDEFINED;
d480 2
a481 2
   wcs->mjdobs = UNDEFINED;
   wcs->mjdavg = UNDEFINED;
d499 1
a499 1
int wcscopy(alloc, wcssrc, wcsdst)
d503 1
d507 3
a509 1
   int i, j, k, naxis, npvmax, npsmax, status;
d519 167
d687 26
a712 6
   npvmax = NPVMAX;
   npsmax = NPSMAX;
   NPVMAX = wcssrc->npvmax;
   NPSMAX = wcssrc->npsmax;
   if (status = wcsini(alloc, naxis, wcsdst)) {
      return status;
a713 2
   NPVMAX = npvmax;
   NPSMAX = npsmax;
d715 1
d719 3
a721 2
   for (j = 0; j < naxis; j++) {
      *(dstp++) = *(srcp++);
d726 4
a729 3
   for (i = 0; i < naxis; i++) {
      for (j = 0; j < naxis; j++) {
         *(dstp++) = *(srcp++);
d735 3
a737 2
   for (i = 0; i < naxis; i++) {
      *(dstp++) = *(srcp++);
d741 4
a744 3
   for (i = 0; i < naxis; i++) {
      strncpy(wcsdst->cunit[i], wcssrc->cunit[i], 72);
      strncpy(wcsdst->ctype[i], wcssrc->ctype[i], 72);
d750 3
a752 2
   for (i = 0; i < naxis; i++) {
      *(dstp++) = *(srcp++);
d762 20
a781 12
   wcsdst->npv = wcssrc->npv;
   for (k = 0; k < wcssrc->npvmax; k++) {
     wcsdst->pv[k].i = wcssrc->pv[k].i;
     wcsdst->pv[k].m = wcssrc->pv[k].m;
     wcsdst->pv[k].value = wcssrc->pv[k].value;
   }

   wcsdst->nps = wcssrc->nps;
   for (k = 0; k < wcssrc->npsmax; k++) {
     wcsdst->ps[k].i = wcssrc->ps[k].i;
     wcsdst->ps[k].m = wcssrc->ps[k].m;
     strncpy(wcsdst->ps[k].value, wcssrc->ps[k].value, 72);
d783 1
d790 4
a793 3
   for (i = 0; i < naxis; i++) {
      for (j = 0; j < naxis; j++) {
         *(dstp++) = *(srcp++);
d799 3
a801 2
   for (i = 0; i < naxis; i++) {
      *(dstp++) = *(srcp++);
d809 5
a813 4
   for (i = 0; i < naxis; i++) {
      strncpy(wcsdst->cname[i], wcssrc->cname[i], 72);
      wcsdst->crder[i] = wcssrc->crder[i];
      wcsdst->csyer[i] = wcssrc->csyer[i];
d822 1
a822 1
   wcsdst->vsource = wcssrc->vsource;
d833 8
a840 1
   return 0;
d1002 7
a1008 4
   for (i = 0; i < wcs->naxis; i++) {
      printf("    cd[%d][]:", i);
      for (j = 0; j < wcs->naxis; j++) {
         printf("  %- 11.4g", wcs->cd[k++]);
a1009 1
      printf("\n");
d1013 6
a1018 3
   printf("            ");
   for (i = 0; i < wcs->naxis; i++) {
      printf("  %- 11.4g", wcs->crota[i]);
a1019 1
   printf("\n");
d1032 7
a1038 5
   for (i = 0; i < wcs->naxis; i++) {
      if (wcs->cname[i][0] == '\0') {
         printf("             UNDEFINED\n");
      } else {
         printf("             \"%s\"\n", wcs->cname[i]);
d1043 8
a1050 6
   printf("           ");
   for (i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->crder[i])) {
         printf("  UNDEFINED   ");
      } else {
         printf("  %- 11.4g", wcs->crder[i]);
d1052 1
a1053 1
   printf("\n");
d1056 8
a1063 6
   printf("           ");
   for (i = 0; i < wcs->naxis; i++) {
      if (undefined(wcs->csyer[i])) {
         printf("  UNDEFINED   ");
      } else {
         printf("  %- 11.4g", wcs->csyer[i]);
d1065 1
a1066 1
   printf("\n");
d1098 2
a1099 2
   if (undefined(wcs->vsource)) {
      printf("    vsource: UNDEFINED\n");
d1101 1
a1101 1
      printf("    vsource: %9f\n", wcs->vsource);
d1110 1
a1110 2
   printf("     obsgeo: 0x%x\n", (int)wcs->obsgeo);
   printf("           ");
d1113 1
a1113 1
         printf("  UNDEFINED   ");
d1115 1
a1115 1
         printf("  %- 11.4g", wcs->obsgeo[i]);
d1470 11
a1480 11
         i = wcs->lng;
         j = wcs->lat;
         rho = wcs->crota[j];

         if (wcs->cdelt[i] == 0.0) return 3;
         lambda = wcs->cdelt[j]/wcs->cdelt[i];

         *(pc + i*naxis + i) = *(pc + j*naxis + j) = cosd(rho);
         *(pc + i*naxis + j) = *(pc + j*naxis + i) = sind(rho);
         *(pc + i*naxis + j) *= -lambda;
         *(pc + j*naxis + i) /=  lambda;
d1484 3
d1509 1
a1509 1
   int    face, i, iso_x, iso_y, k, nx, ny, *statp, status, statx2s, wcslat,
d1613 4
a1616 4
      if (statx2s = celx2s(wcscel, nx, ny, nelem, nelem, imgcrd+wcslng,
                           imgcrd+wcslat, phi, theta, worldlng, worldlat,
                           stat)) {;
         if (statx2s == 5) {
d1619 1
a1619 1
            return statx2s + 3;
d1642 3
a1644 3
      if (statx2s = spcx2s(&(wcs->spc), nx, nelem, nelem, imgcrd+wcspec,
                       world+wcspec, stat)) {
         if (statx2s == 3) {
d1647 1
a1647 1
            return statx2s + 3;
d1674 1
a1674 1
   int    i, isolat, isolng, isospec, k, nlat, nlng, nspec, status, stats2x,
d1682 1
d1727 4
a1730 4
      if (stats2x = cels2x(wcscel, nlng, nlat, nelem, nelem, world+wcslng,
                           world+wcslat, phi, theta, imgcrd+wcslng,
                           imgcrd+wcslat, stat)) {
         if (stats2x == 6) {
d1733 1
a1733 1
            return stats2x + 3;
d1791 3
a1793 3
      if (stats2x = spcs2x(&(wcs->spc), nspec, nelem, nelem, world+wcspec,
                       imgcrd+wcspec, stat)) {
         if (stats2x == 4) {
d1796 1
a1796 1
            return stats2x + 3;
d1809 2
a1810 2
   if (status = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd)) {
      return status;
@


3.4
log
@WCSLIB 3.4
@
text
@d3 1
a3 1
*   WCSLIB 3.4 - an implementation of the FITS WCS convention.
d29 2
a30 1
*   $Id: wcs.c,v 3.3 2003/10/22 07:16:43 mcalabre Exp mcalabre $
d35 1
d43 1
a43 5
#if defined(__convexc__) || defined(__APPLE__)
#include <stdlib.h>
#else
#include <malloc.h>
#endif
d45 3
a47 1
const int WCSSET = 137;
d64 3
d71 21
d98 1
a98 1
   int i, j, k, mem, status;
d100 1
d114 1
a115 1
      wcs->m_cunit = 0;
d118 1
d121 3
d133 13
a145 9
       wcs->crpix == (double *)0 ||
       wcs->pc    == (double *)0 ||
       wcs->cdelt == (double *)0 ||
       wcs->ctype == (char (*)[72])0 ||
       wcs->cunit == (char (*)[72])0 ||
       wcs->crval == (double *)0 ||
       wcs->pv    == (struct pvcard *)0 ||
       wcs->cd    == (double *)0 ||
       wcs->crota == (double *)0) {
d148 4
a151 1
      if (wcs->m_flag == WCSSET && wcs->m_naxis < naxis) {
d163 1
a163 2
            mem = naxis * sizeof(double);
            if ((wcs->crpix = (double *)malloc(mem)) == (double *)0) {
d179 1
a179 2
            mem = naxis * naxis * sizeof(double);
            if ((wcs->pc = (double *)malloc(mem)) == (double *)0) {
d196 1
a196 2
            mem = naxis * sizeof(double);
            if ((wcs->cdelt = (double *)malloc(mem)) == (double *)0) {
d207 2
a208 2
      if (alloc || wcs->ctype == (char (*)[72])0) {
         if (wcs->m_ctype) {
d210 1
a210 1
            wcs->ctype = wcs->m_ctype;
d213 2
a214 2
            mem = naxis*72*sizeof(char);
            if ((wcs->ctype = (char (*)[72])malloc(mem)) == (char (*)[72])0) {
d221 1
a221 1
            wcs->m_ctype = wcs->ctype;
d225 2
a226 2
      if (alloc || wcs->cunit == (char (*)[72])0) {
         if (wcs->m_cunit) {
d228 1
a228 1
            wcs->cunit = wcs->m_cunit;
d231 2
a232 2
            mem = naxis*72*sizeof(char);
            if ((wcs->cunit = (char (*)[72])malloc(mem)) == (char (*)[72])0) {
d239 1
a239 1
            wcs->m_cunit = wcs->cunit;
d249 1
a249 2
            mem = naxis*sizeof(double);
            if ((wcs->crval = (double *)malloc(mem)) == (double *)0) {
d266 6
a271 5
            mem = NPVMAX*sizeof(struct pvcard);
            if ((wcs->pv = (struct pvcard *)malloc(mem)) ==
                           (struct pvcard *)0) {
               wcsfree(wcs);
               return 2;
d274 2
d282 22
d310 1
a310 2
            mem = naxis * naxis * sizeof(double);
            if ((wcs->cd = (double *)malloc(mem)) == (double *)0) {
d327 1
a327 2
            mem = naxis * sizeof(double);
            if ((wcs->crota = (double *)malloc(mem)) == (double *)0) {
d337 52
d406 1
a406 1
   /* CTYPEi and CUNITi are blank by default. */
d408 2
a409 2
      strcpy(wcs->ctype[i], "");
      strcpy(wcs->cunit[i], "");
d413 1
a413 1
   /* CRVALi defaults to 0.0. */
d429 1
a429 1
   for (k = 0; k < NPVMAX; k++) {
d435 7
d454 22
d500 1
a500 1
   int i, j, k, naxis, status;
d510 5
d518 2
d521 1
d542 1
d544 1
a545 1
      strncpy(wcsdst->cunit[i], wcssrc->cunit[i], 72);
d548 1
d555 1
d561 1
d563 1
a563 1
   for (k = 0; k < NPVMAX; k++) {
d569 8
d593 27
d633 39
a671 26
   /* Free memory allocated by wcsini(). */
   if (wcs->m_flag == WCSSET) {
      if (wcs->crpix == wcs->m_crpix) wcs->crpix = 0;
      if (wcs->pc    == wcs->m_pc)    wcs->pc    = 0;
      if (wcs->cdelt == wcs->m_cdelt) wcs->cdelt = 0;
      if (wcs->ctype == wcs->m_ctype) wcs->ctype = 0;
      if (wcs->cunit == wcs->m_cunit) wcs->cunit = 0;
      if (wcs->crval == wcs->m_crval) wcs->crval = 0;
      if (wcs->pv    == wcs->m_pv)    wcs->pv    = 0;
      if (wcs->cd    == wcs->m_cd)    wcs->cd    = 0;
      if (wcs->crota == wcs->m_crota) wcs->crota = 0;

      if (wcs->m_crpix) free(wcs->m_crpix);
      if (wcs->m_pc)    free(wcs->m_pc);
      if (wcs->m_cdelt) free(wcs->m_cdelt);
      if (wcs->m_ctype) free(wcs->m_ctype);
      if (wcs->m_cunit) free(wcs->m_cunit);
      if (wcs->m_crval) free(wcs->m_crval);
      if (wcs->m_pv)    free(wcs->m_pv);
      if (wcs->m_cd)    free(wcs->m_cd);
      if (wcs->m_crota) free(wcs->m_crota);
   }

   if (wcs->lin.crpix == wcs->m_crpix) wcs->lin.crpix = 0;
   if (wcs->lin.pc    == wcs->m_pc)    wcs->lin.pc    = 0;
   if (wcs->lin.cdelt == wcs->m_cdelt) wcs->lin.cdelt = 0;
d678 1
a679 1
   wcs->m_cunit = 0;
d682 1
d685 3
d719 1
d737 2
a738 1
   printf("      ctype: 0x%x\n", (int)wcs->ctype);
d740 1
a740 1
      printf("             \"%s\"\n", wcs->ctype[i]);
d743 1
a743 1
   printf("      cunit: 0x%x\n", (int)wcs->cunit);
d745 1
a745 1
      printf("             \"%s\"\n", wcs->cunit[i]);
d748 1
d756 1
d759 4
a762 2
   printf("    restfrq: %9f\n", wcs->restfrq);
   printf("    restwav: %9f\n", wcs->restwav);
d764 1
d770 7
d778 1
d798 113
d922 1
d937 3
a942 3
   printf("    m_cunit: 0x%x", (int)wcs->m_cunit);
   if (wcs->m_cunit == wcs->cunit) printf("  (= cunit)");
   printf("\n");
d946 3
d950 1
d955 1
d960 1
d989 3
a991 3
   /* Parse the CTYPEi cards. */
   strcpy(pcode, "");
   strcpy(requir, "");
d1101 1
a1101 1
         strcpy(requir, "");
d1118 1
a1118 1
      /* CRVALi, LONPOLE, and LATPOLE cards. */
d1124 1
a1124 1
      /* PVi_m cards. */
d1129 5
d1135 1
a1135 1
            /* PVi_m associated with latitude axis. */
d1141 1
a1141 1
            /* PVi_m associated with longitude axis. */
d1153 1
a1153 1
               /* If present, overrides the LONPOLE card. */
d1157 1
a1157 1
               /* If present, overrides the LATPOLE card. */
d1200 1
a1200 1
      /* CRVALi, RESTFRQ, and RESTWAV cards. */
d1205 1
a1205 1
      /* PVi_m cards. */
d1211 1
a1211 1
            /* PVi_m associated with grism axis. */
d1226 2
a1227 2
   wcs->altlin &= 6;
   if (wcs->altlin) {
d1231 1
a1231 1
         /* Copy CDi_j to PCi_j and reset CDELTi. */
d1241 1
a1241 1
         /* Construct PCi_j from CROTAi. */
@


3.3
log
@WCSLIB 3.3: in wcsini(), if wcs->flag == -1 also set wcs->lin.flag = -1 to
force initialization of the memory managed by linset(); wcsset() now
explicitly initializes the celprm and spcprm structs via celini() and
spcini(); wcsprt() checks that the wcsprm struct has been initialized.
@
text
@d3 2
a4 2
*   WCSLIB 3.3 - an implementation of the FITS WCS convention.
*   Copyright (C) 1995-2003, Mark Calabretta
d29 1
a29 1
*   $Id: wcs.c,v 3.2 2003/09/09 04:34:11 mcalabre Exp mcalabre $
@


3.2
log
@WCSLIB 3.2: in wcsini(), initialize memory management if wcsprm.flag == -1;
renamed wcscpy() to wcscopy() to avoid a conflict with the POSIX "wide
character string" function of the same name (wchar.h); wcsp2s() and wcss2p()
no longer return prematurely if some of the input coordinate values are
invalid; test for null wcsprm pointer given as function argument;
rationalized function return codes and messages.
@
text
@d3 1
a3 1
*   WCSLIB 3.2 - an implementation of the FITS WCS convention.
d29 1
a29 1
*   $Id: wcs.c,v 3.1 2003/04/28 03:50:41 mcalabre Exp mcalabre $
d97 4
d505 5
a684 3

            sprintf(wcsspc->type, "%.4s", ctypei);
            sprintf(wcsspc->code, "%.3s", ctypei+5);
d781 3
a783 1
      /* Parse the CRVALi, LONPOLE, and LATPOLE cards. */
d789 1
a789 1
      /* Parse the PVi_m cards. */
d855 6
a860 1
      /* Parse the CRVALi, RESTFRQ, and RESTWAV cards. */
d865 1
a865 1
      /* Parse the PVi_m cards. */
@


3.1
log
@WCSLIB 3.1
Added support for CUNITi cards to wcsprm (but not currently implemented).
@
text
@d3 1
a3 1
*   WCSLIB 3.1 - an implementation of the FITS WCS convention.
d29 1
a29 1
*   $Id: wcs.c,v 3.0 2003/04/01 04:10:53 mcalabre Exp $
d50 1
a50 1
const char *wcsini_errmsg[] = {
d52 1
a52 37
   "Memory allocation error"};

const char *wcscpy_errmsg[] = {
   0,
   "Memory allocation error"};

const char *wcsset_errmsg[] = {
   0,
   "Memory allocation error",
   "Linear transformation matrix is singular",
   "Inconsistent or unrecognized coordinate axis types",
   "Invalid parameter value",
   "Invalid coordinate transformation parameters",
   "Ill-conditioned coordinate transformation parameters"};

const char *wcsp2s_errmsg[] = {
   0,
   "Memory allocation error",
   "Linear transformation matrix is singular",
   "Inconsistent or unrecognized coordinate axis types",
   "Invalid parameter value",
   "Invalid coordinate transformation parameters",
   "Ill-conditioned coordinate transformation parameters",
   "Invalid pixel coordinate"};

const char *wcss2p_errmsg[] = {
   0,
   "Memory allocation error",
   "Linear transformation matrix is singular",
   "Inconsistent or unrecognized coordinate axis types",
   "Invalid parameter value",
   "Invalid coordinate transformation parameters",
   "Ill-conditioned coordinate transformation parameters",
   "Invalid world coordinate"};

const char *wcsmix_errmsg[] = {
   0,
d59 2
d74 1
a74 1
   int i, j, k, mem;
d77 2
d80 1
a80 1
      return 1;
d83 1
a83 1
   if (wcs->m_flag != WCSSET) {
d125 1
a125 1
               return 1;
d143 1
a143 1
               return 1;
d161 1
a161 1
               return 1;
d179 1
a179 1
               return 1;
d197 1
a197 1
               return 1;
d215 1
a215 1
               return 1;
d234 1
a234 1
               return 1;
d252 1
a252 1
               return 1;
d270 1
a270 1
               return 1;
d286 6
a291 5
   wcs->lin.crpix = wcs->crpix;
   wcs->lin.pc    = wcs->pc;
   wcs->lin.cdelt = wcs->cdelt;
   if (linini(0, naxis, &(wcs->lin))) {
      return 1;
d295 1
a295 1
   /* CTYPEi and CUNITi is blank by default. */
d353 1
a353 1
int wcscpy(alloc, wcssrc, wcsdst)
d364 4
a367 3
   naxis = wcssrc->naxis;
   if (naxis <= 0) {
      return 1;
d444 2
d469 4
d485 1
a485 1
   linfree(&(wcs->lin));
d487 1
a487 1
   return 0;
d635 1
a635 1
   int err, i, j, k, m, naxis, *ndx = 0;
d643 2
d664 1
a664 1
               return 3;
d749 1
a749 1
            return 3;
d756 1
a756 1
            return 3;
d769 1
a769 1
      return 3;
d813 1
a813 1
               return 5;
d826 1
a826 1
            return 4;
d839 2
a840 2
      if (err = celset(wcscel)) {
         return err + 3;
d866 2
a867 2
      if (err = spcset(wcsspc)) {
         return err + 3;
d893 1
a893 1
         if (wcs->cdelt[i] == 0.0) return 2;
d903 2
a904 2
   if (err = linset(&(wcs->lin))) {
      return err;
d925 2
a926 1
   int    err, face, i, iso_x, iso_y, k, nx, ny, wcslat, wcslng, wcspec;
d932 1
d934 1
a934 1
      if (err = wcsset(wcs)) return err;
d939 2
a940 2
   if (err = linp2x(&(wcs->lin), ncoord, nelem, pixcrd, imgcrd)) {
      return err;
d978 2
a979 1
         for (k = 0; k < ncoord; k++) {
d982 25
a1006 23
               return 7;
            }

            switch (face) {
            case 0:
               *(img+wcslat) += offset;
               break;
            case 1:
               break;
            case 2:
               *(img+wcslng) += offset;
               break;
            case 3:
               *(img+wcslng) += offset*2;
               break;
            case 4:
               *(img+wcslng) += offset*3;
               break;
            case 5:
               *(img+wcslat) -= offset;
               break;
            default:
               return 7;
d1029 8
a1036 4
      if (err = celx2s(wcscel, nx, ny, nelem, nelem,
                       imgcrd+wcslng, imgcrd+wcslat, phi, theta,
                       worldlng, worldlat, stat)) {
         return err + 3;
d1058 1
a1058 1
      if (err = spcx2s(&(wcs->spc), nx, nelem, nelem, imgcrd+wcspec,
d1060 5
a1064 1
         return (err == 1) ? 4 : 7;
d1074 1
a1074 1
   return 0;
d1090 2
a1091 2
   int    err, i, isolat, isolng, isospec, k, nlat, nlng, nspec, wcslat,
          wcslng, wcspec;
d1096 1
d1098 1
d1100 1
a1100 1
      if (err = wcsset(wcs)) return err;
d1142 8
a1149 5
      if (err = cels2x(wcscel, nlng, nlat, nelem, nelem,
                       world+wcslng, world+wcslat, phi, theta,
                       imgcrd+wcslng, imgcrd+wcslat,
                       stat)) {
         return err + 3;
d1206 7
a1212 3
      if (err = spcs2x(&(wcs->spc), nspec, nelem, nelem,
                       world+wcspec, imgcrd+wcspec, stat)) {
         return (err == 1) ? 4 : 7;
d1224 2
a1225 2
   if (err = linx2p(&(wcs->lin), ncoord, nelem, imgcrd, pixcrd)) {
      return err;
d1228 1
a1228 1
   return 0;
d1248 1
a1248 1
   int    crossed, err, istep, iter, j, k, nstep, retry, stat[1];
d1262 1
d1264 1
a1264 1
      if (err = wcsset(wcs)) return err;
d1310 3
a1312 3
         if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
            return err;
d1321 3
a1323 3
         if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
            return err;
d1348 3
a1350 3
               if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                stat)) {
                  return err;
d1390 3
a1392 3
                  if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
                     return err;
d1441 3
a1443 3
               if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                stat)) {
                  return err;
d1450 3
a1452 3
               if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                stat)) {
                  return err;
d1459 3
a1461 3
                  if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
                     return err;
d1469 3
a1471 3
                  if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
                     return err;
d1503 3
a1505 3
         if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
            return err;
d1514 3
a1516 3
         if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
            return err;
d1540 3
a1542 3
               if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                stat)) {
                  return err;
d1582 3
a1584 3
                  if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
                     return err;
d1633 3
a1635 3
               if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                stat)) {
                  return err;
d1642 3
a1644 3
               if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd, pixcrd,
                                stat)) {
                  return err;
d1651 3
a1653 3
                  if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
                     return err;
d1661 3
a1663 3
                  if (err = wcss2p(wcs, 1, 0, world, phi, theta, imgcrd,
                                   pixcrd, stat)) {
                     return err;
d1706 1
a1706 1
      err = sphx2s(wcs->cel.euler, 1, 1, 1, 1, phi, theta, &lng, &lat);
d1729 3
a1731 3
      if (err = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                       stat)) {
         return err;
d1748 3
a1750 3
         if (err = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
            return err;
d1781 3
a1783 3
         if (err = wcss2p(&wcs0, 1, 0, world, phi, theta, imgcrd, pixcrd,
                          stat)) {
            return err;
d1808 1
a1808 1
   return 8;
@


3.0
log
@WCSLIB 3.0
@
text
@d3 1
a3 1
*   WCSLIB 3.0 - an implementation of the FITS WCS convention.
d29 1
a29 1
*   $Id: wcs.c,v 2.21 2001/09/05 04:38:38 mcalabre Exp $
d122 1
d136 1
d220 18
d326 1
a326 1
   /* CTYPEi is blank by default. */
d329 1
d426 1
d480 1
d490 1
d503 1
d553 1
a553 1
      printf("              \"%s\"\n", wcs->ctype[i]);
d556 5
d625 3
@


2.23
log
@Updated date in copyright notice.
@
text
@d1 1
a1 1
/*=============================================================================
d3 2
a4 2
*   WCSLIB - an implementation of the FITS WCS proposal.
*   Copyright (C) 1995-2002, Mark Calabretta
d22 4
a25 4
*      Postal address: Dr. Mark Calabretta,
*                      Australia Telescope National Facility,
*                      P.O. Box 76,
*                      Epping, NSW, 2121,
a27 356
*=============================================================================
*
*   C routines which implement the FITS World Coordinate System (WCS)
*   convention.
*
*   Summary of routines
*   -------------------
*   wcsfwd() and wcsrev() are high level driver routines for the WCS linear
*   transformation, spherical coordinate transformation, and spherical
*   projection routines.
*
*   Given either the celestial longitude or latitude plus an element of the
*   pixel coordinate a hybrid routine, wcsmix(), iteratively solves for the
*   unknown elements.
*
*   An initialization routine, wcsset(), computes indices from the ctype
*   array but need not be called explicitly - see the explanation of
*   wcs.flag below.
*
*
*   Initialization routine; wcsset()
*   --------------------------------
*   Initializes elements of a wcsprm data structure which holds indices into
*   the coordinate arrays.  Note that this routine need not be called directly;
*   it will be invoked by wcsfwd() and wcsrev() if the "flag" structure member
*   is anything other than a predefined magic value.
*
*   Given:
*      naxis    const int
*                        Number of image axes.
*      ctype[][9]
*               const char
*                        Coordinate axis types corresponding to the FITS
*                        CTYPEn header cards.
*
*   Returned:
*      wcs      wcsprm*  Indices for the celestial coordinates obtained
*                        by parsing the ctype[] array (see below).
*
*   Function return value:
*               int      Error status
*                           0: Success.
*                           1: Inconsistent or unrecognized coordinate axis
*                              types.
*
*
*   Forward transformation; wcsfwd()
*   --------------------------------
*   Compute the pixel coordinate for given world coordinates.
*
*   Given:
*      ctype[][9]
*               const char
*                        Coordinate axis types corresponding to the FITS
*                        CTYPEn header cards.
*
*   Given or returned:
*      wcs      wcsprm*  Indices for the celestial coordinates obtained
*                        by parsing the ctype[] array (see below).
*
*   Given:
*      world    const double[]
*                        World coordinates.  world[wcs->lng] and
*                        world[wcs->lat] are the celestial longitude and
*                        latitude, in degrees.
*
*   Given:
*      crval    const double[]
*                        Coordinate reference values corresponding to the FITS
*                        CRVALn header cards (see note 2).
*
*   Given and returned:
*      cel      celprm*  Spherical coordinate transformation parameters (usage
*                        is described in the prologue to "cel.c").
*
*   Returned:
*      phi,     double*  Longitude and latitude in the native coordinate
*      theta             system of the projection, in degrees.
*
*   Given and returned:
*      prj      prjprm*  Projection parameters (usage is described in the
*                        prologue to "proj.c").
*
*   Returned:
*      imgcrd   double[] Image coordinate.  imgcrd[wcs->lng] and
*                        imgcrd[wcs->lat] are the projected x-, and
*                        y-coordinates, in "degrees".  For quadcube
*                        projections with a CUBEFACE axis the face number is
*                        also returned in imgcrd[wcs->cubeface].
*
*   Given and returned:
*      lin      linprm*  Linear transformation parameters (usage is described
*                        in the prologue to "lin.c").
*
*   Returned:
*      pixcrd   double[] Pixel coordinate.
*
*   Function return value:
*               int      Error status
*                           0: Success.
*                           1: Invalid coordinate transformation parameters.
*                           2: Invalid projection parameters.
*                           3: Invalid world coordinate.
*                           4: Invalid linear transformation parameters.
*
*
*   Reverse transformation; wcsrev()
*   --------------------------------
*   Compute world coordinates for a given pixel coordinate.
*
*   Given:
*      ctype[][9]
*               const char
*                        Coordinate axis types corresponding to the FITS
*                        CTYPEn header cards.
*
*   Given or returned:
*      wcs      wcsprm*  Indices for the celestial coordinates obtained
*                        by parsing the ctype[] array (see below).
*
*   Given:
*      pixcrd   const double[]
*                        Pixel coordinate.
*
*   Given and returned:
*      lin      linprm*  Linear transformation parameters (usage is described
*                        in the prologue to "lin.c").
*
*   Returned:
*      imgcrd   double[] Image coordinate.  imgcrd[wcs->lng] and
*                        imgcrd[wcs->lat] are the projected x-, and
*                        y-coordinates, in "degrees".
*
*   Given and returned:
*      prj      prjprm*  Projection parameters (usage is described in the
*                        prologue to "proj.c").
*
*   Returned:
*      phi,     double*  Longitude and latitude in the native coordinate
*      theta             system of the projection, in degrees.
*
*   Given:
*      crval    const double[]
*                        Coordinate reference values corresponding to the FITS
*                        CRVALn header cards (see note 2).
*
*   Given and returned:
*      cel      celprm*  Spherical coordinate transformation parameters
*                        (usage is described in the prologue to "cel.c").
*
*   Returned:
*      world    double[] World coordinates.  world[wcs->lng] and
*                        world[wcs->lat] are the celestial longitude and
*                        latitude, in degrees.
*
*   Function return value:
*               int      Error status
*                           0: Success.
*                           1: Invalid coordinate transformation parameters.
*                           2: Invalid projection parameters.
*                           3: Invalid pixel coordinate.
*                           4: Invalid linear transformation parameters.
*
*
*   Hybrid transformation; wcsmix()
*   -------------------------------
*   Given either the celestial longitude or latitude plus an element of the
*   pixel coordinate solve for the remaining elements by iterating on the
*   unknown celestial coordinate element using wcsfwd().
*
*   Given:
*      ctype[][9]
*               const char
*                        Coordinate axis types corresponding to the FITS
*                        CTYPEn header cards.
*
*   Given or returned:
*      wcs      wcsprm*  Indices for the celestial coordinates obtained
*                        by parsing the ctype[] array (see below).
*
*   Given:
*      mixpix   const int
*                        Which element of the pixel coordinate is given.
*      mixcel   const int
*                        Which element of the celestial coordinate is
*                        given:
*                           1: Celestial longitude is given in
*                              world[wcs->lng], latitude returned in
*                              world[wcs->lat].
*                           2: Celestial latitude is given in
*                              world[wcs->lat], longitude returned in
*                              world[wcs->lng].
*      vspan[2] const double
*                        Solution interval for the celestial coordinate, in
*                        degrees.  The ordering of the two limits is
*                        irrelevant.  Longitude ranges may be specified with
*                        any convenient normalization, for example [-120,+120]
*                        is the same as [240,480], except that the solution
*                        will be returned with the same normalization, i.e.
*                        lie within the interval specified.
*      vstep    const double
*                        Step size for solution search, in degrees.  If zero,
*                        a sensible, although perhaps non-optimal default will
*                        be used.
*      viter    int
*                        If a solution is not found then the step size will be
*                        halved and the search recommenced.  viter controls
*                        how many times the step size is halved.  The allowed
*                        range is 5 - 10.
*
*   Given and returned:
*      world    double[] World coordinates.  world[wcs->lng] and
*                        world[wcs->lat] are the celestial longitude and
*                        latitude, in degrees.  Which is given and which
*                        returned depends on the value of mixcel.  All other
*                        elements are given.
*
*   Given:
*      crval    const double[]
*                        Coordinate reference values corresponding to the FITS
*                        CRVALn header cards (see note 2).
*
*   Given and returned:
*      cel      celprm*  Spherical coordinate transformation parameters
*                        (usage is described in the prologue to "cel.c").
*
*   Returned:
*      phi,     double*  Longitude and latitude in the native coordinate
*      theta             system of the projection, in degrees.
*
*   Given and returned:
*      prj      prjprm*  Projection parameters (usage is described in the
*                        prologue to "proj.c").
*
*   Returned:
*      imgcrd   double[] Image coordinate.  imgcrd[wcs->lng] and
*                        imgcrd[wcs->lat] are the projected x-, and
*                        y-coordinates, in "degrees".
*
*   Given and returned:
*      lin      linprm*  Linear transformation parameters (usage is described
*                        in the prologue to "lin.c").
*
*   Given and returned:
*      pixcrd   double[] Pixel coordinate.  The element indicated by mixpix is
*                        given and the remaining elements are returned.
*
*   Function return value:
*               int      Error status
*                           0: Success.
*                           1: Invalid coordinate transformation parameters.
*                           2: Invalid projection parameters.
*                           3: Coordinate transformation error.
*                           4: Invalid linear transformation parameters.
*                           5: No solution found in the specified interval.
*
*
*   Notes
*   -----
*    1) The CTYPEn must in be upper case and there must be 0 or 1 pair of
*       matched celestial axis types.  The ctype[][9] should be padded with
*       blanks on the right and null-terminated.
*
*    2) Elements of the crval[] array which correspond to celestial axes are
*       ignored, the reference coordinate values in cel->ref[0] and
*       cel->ref[1] are the ones used.
*
*    3) These functions recognize the NCP projection and convert it to the
*       equivalent SIN projection.
*
*       They also recognize GLS as a synonym for SFL.
*
*    4) The quadcube projections (TSC, CSC, QSC) may be represented in FITS in
*       either of two ways:
*
*          a) The six faces may be laid out in one plane and numbered as
*             follows:
*
*                                       0
*
*                              4  3  2  1  4  3  2
*
*                                       5
*
*             Faces 2, 3 and 4 may appear on one side or the other (or both).
*             The forward routines map faces 2, 3 and 4 to the left but the
*             inverse routines accept them on either side.
*
*          b) The "COBE" convention in which the six faces are stored in a
*             three-dimensional structure using a "CUBEFACE" axis indexed from
*             0 to 5 as above.
*
*       These routines support both methods; wcsset() determines which is
*       being used by the presence or absence of a CUBEFACE axis in ctype[].
*       wcsfwd() and wcsrev() translate the CUBEFACE axis representation to
*       the single plane representation understood by the lower-level WCSLIB
*       projection routines.
*
*
*   WCS indexing parameters
*   -----------------------
*   The wcsprm struct consists of the following:
*
*      int flag
*         The wcsprm struct contains indexes and other information derived
*         from the CTYPEn.  Whenever any of the ctype[] are set or changed
*         this flag must be set to zero to signal the initialization routine,
*         wcsset() to redetermine the indices.  The flag is set to 999 if
*         there is no celestial axis pair in the CTYPEn.
*
*      char pcode[4]
*         The WCS projection code.
*
*      char lngtyp[5], lattyp[5]
*         WCS celestial axis types.
*
*      int lng,lat
*         Indices into the imgcrd[], and world[] arrays as described above.
*         These may also serve as indices for the celestial longitude and
*         latitude axes in the pixcrd[] array provided that the PC matrix
*         does not transpose axes.
*
*      int cubeface
*         Index into the pixcrd[] array for the CUBEFACE axis.  This is
*         optionally used for the quadcube projections where each cube face is
*         stored on a separate axis.
*
*
*   wcsmix() algorithm
*   ------------------
*      Initially the specified solution interval is checked to see if it's a
*      "crossing" interval.  If it isn't, a search is made for a crossing
*      solution by iterating on the unknown celestial coordinate starting at
*      the upper limit of the solution interval and decrementing by the
*      specified step size.  A crossing is indicated if the trial value of the
*      pixel coordinate steps through the value specified.  If a crossing
*      interval is found then the solution is determined by a modified form of
*      "regula falsi" division of the crossing interval.  If no crossing
*      interval was found within the specified solution interval then a search
*      is made for a "non-crossing" solution as may arise from a point of
*      tangency.  The process is complicated by having to make allowance for
*      the discontinuities that occur in all map projections.
*
*      Once one solution has been determined others may be found by subsequent
*      invokations of wcsmix() with suitably restricted solution intervals.
*
*      Note the circumstance which arises when the solution point lies at a
*      native pole of a projection in which the pole is represented as a
*      finite curve, for example the zenithals and conics.  In such cases two
*      or more valid solutions may exist but WCSMIX only ever returns one.
*
*      Because of its generality wcsmix() is very compute-intensive.  For
*      compute-limited applications more efficient special-case solvers could
*      be written for simple projections, for example non-oblique cylindrical
*      projections.
*
d29 1
a29 1
*   $Id: wcs.c,v 2.22 2002/04/03 00:07:18 mcalabre Exp mcalabre $
d33 1
d35 1
a35 1
#include <stdio.h>
d41 8
d50 8
d60 6
a65 1
   "Inconsistent or unrecognized coordinate axis types"};
d67 1
a67 1
const char *wcsfwd_errmsg[] = {
d69 4
d74 2
a75 3
   "Invalid projection parameters",
   "Invalid world coordinate",
   "Invalid linear transformation parameters"};
d77 1
a77 1
const char *wcsrev_errmsg[] = {
d79 4
d84 2
a85 3
   "Invalid projection parameters",
   "Invalid pixel coordinate",
   "Invalid linear transformation parameters"};
d89 4
d94 2
a95 3
   "Invalid projection parameters",
   "Coordinate transformation error",
   "Invalid linear transformation parameters",
d98 513
d612 2
a613 3
#ifdef SIGNBIT
#define signbit(X) ((X) < 0.0 ? 1 : 0)
#endif
d615 1
d617 1
a617 1
int wcsset (naxis, ctype, wcs)
a618 2
const int naxis;
const char ctype[][9];
d622 2
a623 2
   int  nalias = 2;
   char aliases [2][4] = {"NCP", "GLS"};
d625 7
a631 2
   int j, k, *ndx;
   char requir[9];
d633 3
a635 1
   strcpy(wcs->pcode, "");
d637 3
a639 2
   wcs->lng = -1;
   wcs->lat = -1;
d642 7
a648 3
   for (j = 0; j < naxis; j++) {
      if (ctype[j][4] != '-') {
         if (strcmp(ctype[j], "CUBEFACE") == 0) {
d650 1
a650 1
               wcs->cubeface = j;
d653 1
a653 1
               return 1;
d659 21
a679 3
      /* Got an axis qualifier, is it a recognized WCS projection? */
      for (k = 0; k < npcode; k++) {
         if (strncmp(&ctype[j][5], pcodes[k], 3) == 0) break;
d682 1
a682 1
      if (k == npcode) {
d685 1
a685 1
            if (strncmp(&ctype[j][5], aliases[k], 3) == 0) break;
d695 2
a696 2
      if (strcmp(wcs->pcode, "") == 0) {
         sprintf(wcs->pcode, "%.3s", &ctype[j][5]);
d698 2
a699 2
         if (strncmp(ctype[j], "RA--", 4) == 0) {
            wcs->lng = j;
d703 3
a705 3
            sprintf(requir, "DEC--%s", wcs->pcode);
         } else if (strncmp(ctype[j], "DEC-", 4) == 0) {
            wcs->lat = j;
d709 5
a713 5
            sprintf(requir, "RA---%s", wcs->pcode);
         } else if (strncmp(&ctype[j][1], "LON", 3) == 0) {
            wcs->lng = j;
            sprintf(wcs->lngtyp, "%cLON", ctype[j][0]);
            sprintf(wcs->lattyp, "%cLAT", ctype[j][0]);
d715 5
a719 5
            sprintf(requir, "%s-%s", wcs->lattyp, wcs->pcode);
         } else if (strncmp(&ctype[j][1], "LAT", 3) == 0) {
            wcs->lat = j;
            sprintf(wcs->lngtyp, "%cLON", ctype[j][0]);
            sprintf(wcs->lattyp, "%cLAT", ctype[j][0]);
d721 5
a725 5
            sprintf(requir, "%s-%s", wcs->lngtyp, wcs->pcode);
         } else if (strncmp(&ctype[j][2], "LN", 2) == 0) {
            wcs->lng = j;
            sprintf(wcs->lngtyp, "%c%cLN", ctype[j][0], ctype[j][1]);
            sprintf(wcs->lattyp, "%c%cLT", ctype[j][0], ctype[j][1]);
d727 5
a731 5
            sprintf(requir, "%s-%s", wcs->lattyp, wcs->pcode);
         } else if (strncmp(&ctype[j][2], "LT", 2) == 0) {
            wcs->lat = j;
            sprintf(wcs->lngtyp, "%c%cLN", ctype[j][0], ctype[j][1]);
            sprintf(wcs->lattyp, "%c%cLT", ctype[j][0], ctype[j][1]);
d733 1
a733 1
            sprintf(requir, "%s-%s", wcs->lngtyp, wcs->pcode);
d736 3
a738 1
            return 1;
d741 1
a741 1
         if (strncmp(ctype[j], requir, 8) != 0) {
d743 3
a745 1
            return 1;
d748 1
a748 1
         *ndx = j;
d753 1
d756 102
a857 1
      return 1;
d860 30
a889 3
   /* Do simple alias translations. */
   if (strncmp(wcs->pcode, "GLS", 3) == 0) {
      strcpy(wcs->pcode, "SFL");
d892 2
a893 5
   if (strcmp(wcs->pcode, "")) {
      wcs->flag = WCSSET;
   } else {
      /* Signal for no celestial axis pair. */
      wcs->flag = 999;
d896 2
d903 1
a903 2
int wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj, imgcrd, lin,
    pixcrd)
d905 3
a907 7
const char ctype[][9];
struct wcsprm* wcs;
const double world[];
const double crval[];
struct celprm *cel;
double *phi, *theta;
struct prjprm *prj;
d909 3
a911 2
struct linprm *lin;
double pixcrd[];
d914 4
a917 2
   int    err, j;
   double offset;
d921 1
a921 1
      if (wcsset(lin->naxis, ctype, wcs)) return 1;
d924 4
a927 5
   /* Convert to relative physical coordinates. */
   for (j = 0; j < lin->naxis; j++) {
      if (j == wcs->lng) continue;
      if (j == wcs->lat) continue;
      imgcrd[j] = world[j] - crval[j];
d930 4
a933 7
   if (wcs->flag != 999) {
      /* Compute projected coordinates. */
      if (strcmp(wcs->pcode, "NCP") == 0) {
         /* Convert NCP to SIN. */
         if (cel->ref[1] == 0.0) {
            return 2;
         }
d935 7
a941 4
         strcpy(wcs->pcode, "SIN");
         prj->p[1] = 0.0;
         prj->p[2] = cosd(cel->ref[1])/sind(cel->ref[1]);
         prj->flag = (prj->flag < 0) ? -1 : 0;
d944 3
a946 3
      if (err = celfwd(wcs->pcode, world[wcs->lng], world[wcs->lat], cel,
                   phi, theta, prj, &imgcrd[wcs->lng], &imgcrd[wcs->lat])) {
         return err;
d949 5
d957 1
a957 1
         if (prj->r0 == 0.0) {
d960 1
a960 1
            offset = prj->r0*PI/2.0;
d963 31
a993 18
         /* Stack faces in a cube. */
         if (imgcrd[wcs->lat] < -0.5*offset) {
            imgcrd[wcs->lat] += offset;
            imgcrd[wcs->cubeface] = 5.0;
         } else if (imgcrd[wcs->lat] > 0.5*offset) {
            imgcrd[wcs->lat] -= offset;
            imgcrd[wcs->cubeface] = 0.0;
         } else if (imgcrd[wcs->lng] > 2.5*offset) {
            imgcrd[wcs->lng] -= 3.0*offset;
            imgcrd[wcs->cubeface] = 4.0;
         } else if (imgcrd[wcs->lng] > 1.5*offset) {
            imgcrd[wcs->lng] -= 2.0*offset;
            imgcrd[wcs->cubeface] = 3.0;
         } else if (imgcrd[wcs->lng] > 0.5*offset) {
            imgcrd[wcs->lng] -= offset;
            imgcrd[wcs->cubeface] = 2.0;
         } else {
            imgcrd[wcs->cubeface] = 1.0;
d996 31
d1029 19
a1047 3
   /* Apply forward linear transformation. */
   if (linfwd(imgcrd, lin, pixcrd)) {
      return 4;
d1055 1
a1055 2
int wcsrev(ctype, wcs, pixcrd, lin, imgcrd, prj, phi, theta, crval, cel,
    world)
d1057 4
a1060 4
const char ctype[][9];
struct wcsprm *wcs;
const double pixcrd[];
struct linprm *lin;
d1062 2
a1063 5
struct prjprm *prj;
double *phi, *theta;
const double crval[];
struct celprm *cel;
double world[];
d1066 2
a1067 1
   int    err, face, j;
d1069 2
d1074 1
a1074 1
      if (wcsset(lin->naxis, ctype, wcs)) return 1;
d1077 21
a1097 3
   /* Apply reverse linear transformation. */
   if (linrev(pixcrd, lin, imgcrd)) {
      return 4;
d1100 22
a1121 6
   /* Convert to world coordinates. */
   for (j = 0; j < lin->naxis; j++) {
      if (j == wcs->lng) continue;
      if (j == wcs->lat) continue;
      world[j] = imgcrd[j] + crval[j];
   }
d1123 8
a1131 1
   if (wcs->flag != 999) {
a1133 5
         face = (int)(imgcrd[wcs->cubeface] + 0.5);
         if (fabs(imgcrd[wcs->cubeface]-face) > 1e-10) {
            return 3;
         }

d1135 1
a1135 1
         if (prj->r0 == 0.0) {
d1138 1
a1138 1
            offset = prj->r0*PI/2.0;
d1141 23
a1163 21
         /* Lay out faces in a plane. */
         switch (face) {
         case 0:
            imgcrd[wcs->lat] += offset;
            break;
         case 1:
            break;
         case 2:
            imgcrd[wcs->lng] += offset;
            break;
         case 3:
            imgcrd[wcs->lng] += offset*2;
            break;
         case 4:
            imgcrd[wcs->lng] += offset*3;
            break;
         case 5:
            imgcrd[wcs->lat] -= offset;
            break;
         default:
            return 3;
d1166 2
d1169 7
a1175 6
      /* Compute celestial coordinates. */
      if (strcmp(wcs->pcode, "NCP") == 0) {
         /* Convert NCP to SIN. */
         if (cel->ref[1] == 0.0) {
            return 2;
         }
d1177 3
a1179 4
         strcpy(wcs->pcode, "SIN");
         prj->p[1] = 0.0;
         prj->p[2] = cosd(cel->ref[1])/sind(cel->ref[1]);
         prj->flag = (prj->flag < 0) ? -1 : 0;
d1182 4
a1185 3
      if (err = celrev(wcs->pcode, imgcrd[wcs->lng], imgcrd[wcs->lat], prj,
                   phi, theta, cel, &world[wcs->lng], &world[wcs->lat])) {
         return err;
d1189 6
d1200 2
a1201 2
int wcsmix(ctype, wcs, mixpix, mixcel, vspan, vstep, viter, world, crval, cel,
           phi, theta, prj, imgcrd, lin, pixcrd)
a1202 1
const char ctype[][9];
d1204 3
a1206 2
const int mixpix, mixcel;
const double vspan[2], vstep;
d1209 1
a1209 4
const double crval[];
struct celprm *cel;
double *phi, *theta;
struct prjprm *prj;
a1210 1
struct linprm *lin;
d1215 1
a1215 1
   int    crossed, err, istep, iter, j, k, nstep, retry;
d1218 1
d1223 1
a1223 1
   double d, d0, d0m, d1, d1m, dx;
d1226 1
a1226 1
   struct celprm cel0;
d1230 1
a1230 1
      if (wcsset(lin->naxis, ctype, wcs)) return 1;
d1233 4
d1275 3
a1277 3
         world[wcs->lat] = lat0;
         if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
                          imgcrd, lin, pixcrd)) {
d1286 3
a1288 3
         world[wcs->lat] = lat1;
         if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
                          imgcrd, lin, pixcrd)) {
d1313 3
a1315 3
               world[wcs->lat] = lat0;
               if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                prj, imgcrd, lin, pixcrd)) {
d1355 3
a1357 3
                  world[wcs->lat] = lat;
                  if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                   prj, imgcrd, lin, pixcrd)) {
d1406 3
a1408 3
               world[wcs->lat] = lat0;
               if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                prj, imgcrd, lin, pixcrd)) {
d1415 3
a1417 3
               world[wcs->lat] = lat1;
               if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                prj, imgcrd, lin, pixcrd)) {
d1424 3
a1426 3
                  world[wcs->lat] = lat0m;
                  if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                   prj, imgcrd, lin, pixcrd)) {
d1434 3
a1436 3
                  world[wcs->lat] = lat1m;
                  if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                   prj, imgcrd, lin, pixcrd)) {
d1468 3
a1470 3
         world[wcs->lng] = lng0;
         if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
                          imgcrd, lin, pixcrd)) {
d1479 3
a1481 3
         world[wcs->lng] = lng1;
         if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta, prj,
                          imgcrd, lin, pixcrd)) {
d1505 3
a1507 3
               world[wcs->lng] = lng0;
               if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                          prj, imgcrd, lin, pixcrd)) {
d1547 3
a1549 3
                  world[wcs->lng] = lng;
                  if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                   prj, imgcrd, lin, pixcrd)) {
d1598 3
a1600 3
               world[wcs->lng] = lng0;
               if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                prj, imgcrd, lin, pixcrd)) {
d1607 3
a1609 3
               world[wcs->lng] = lng1;
               if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                prj, imgcrd, lin, pixcrd)) {
d1616 3
a1618 3
                  world[wcs->lng] = lng0m;
                  if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                   prj, imgcrd, lin, pixcrd)) {
d1626 3
a1628 3
                  world[wcs->lng] = lng1m;
                  if (err = wcsfwd(ctype, wcs, world, crval, cel, phi, theta,
                                   prj, imgcrd, lin, pixcrd)) {
d1659 6
a1664 10
   cel0.flag = CELSET;
   cel0.ref[0] = cel->ref[0];
   cel0.ref[1] = cel->ref[1];
   cel0.ref[2] = cel->ref[2];
   cel0.ref[3] = cel->ref[3];
   cel0.euler[0] = -90.0;
   cel0.euler[1] =   0.0;
   cel0.euler[2] =  90.0;
   cel0.euler[3] =   1.0;
   cel0.euler[4] =   0.0;
d1670 1
d1672 1
a1672 1
      err = sphrev(0.0, *theta, cel->euler, &lng, &lat);
d1675 1
a1675 1
         if (fabs(fmod(world[wcs->lng]-lng,360.0)) > tol) continue;
d1678 1
a1678 1
         world[wcs->lat] = lat;
d1680 1
a1680 1
         if (fabs(world[wcs->lat]-lat) > tol) continue;
d1685 1
a1685 1
         world[wcs->lng] = lng;
d1689 2
a1690 2
      lng = world[wcs->lng];
      lat = world[wcs->lat];
d1692 5
a1696 5
      /* Feed native coordinates to wcsfwd() with cel0 set to unity. */
      world[wcs->lng] = -180.0;
      world[wcs->lat] = *theta;
      if (err = wcsfwd(ctype, wcs, world, crval, &cel0, phi, theta, prj,
                       imgcrd, lin, pixcrd)) {
d1704 2
a1705 2
         world[wcs->lng] = lng;
         world[wcs->lat] = lat;
d1713 3
a1715 3
         world[wcs->lng] = phi1;
         if (err = wcsfwd(ctype, wcs, world, crval, &cel0, phi, theta, prj,
                          imgcrd, lin, pixcrd)) {
d1724 2
a1725 2
            world[wcs->lng] = lng;
            world[wcs->lat] = lat;
d1746 3
a1748 3
         world[wcs->lng] = phi0 + lambda*dphi;
         if (err = wcsfwd(ctype, wcs, world, crval, &cel0, phi, theta, prj,
                          imgcrd, lin, pixcrd)) {
d1757 2
a1758 2
            world[wcs->lng] = lng;
            world[wcs->lat] = lat;
d1763 1
a1763 1
            phi0 = world[wcs->lng];
d1766 1
a1766 1
            phi1 = world[wcs->lng];
d1774 25
a1798 1
   return 5;
d1800 26
@


2.22
log
@Fixed a bug with alias translation in wcsset().
@
text
@d4 1
a4 1
*   Copyright (C) 1995-2001, Mark Calabretta
d385 1
a385 1
*   $Id: wcs.c,v 2.21 2001/09/05 04:38:38 mcalabre Exp mcalabre $
@


2.21
log
@Fixed a problem in wcsmix() caused by numerical imprecision which could cause
it not to recognize when convergence was reached; break out of the loop early
if a discontinuity is detected.
@
text
@d385 1
a385 1
*   $Id: wcs.c,v 2.20 2001/06/18 05:03:38 mcalabre Exp mcalabre $
a470 1
      }
d472 4
a475 3
      if (k == nalias) {
         /* Not recognized. */
         continue;
@


2.20
log
@Clarified the usage of vspan in wcsmix().
@
text
@d385 1
a385 1
*   $Id: wcs.c,v 2.19 2001/02/19 00:39:48 mcalabre Exp mcalabre $
d612 1
a612 1
 
d726 1
a726 1
 
d764 2
a765 1
   const double tol = 1.0e-10;
d768 2
a769 2
   double lng, lng0, lng0m, lng1, lng1m;
   double lat, lat0, lat0m, lat1, lat1m;
d772 1
a772 1
   double phi0, phi1;
d896 2
a897 1
                  lat = lat0 + lambda*(lat1 - lat0);
a902 1
                  d = pixcrd[mixpix] - pixmix;
d905 1
d909 8
d1088 2
a1089 1
                  lng = lng0 + lambda*(lng1 - lng0);
a1094 1
                  d = pixcrd[mixpix] - pixmix;
d1097 1
d1101 8
d1258 1
a1258 1
         phi1 = (float) k;
d1290 3
a1292 2
 
         world[wcs->lng] = phi0 + lambda*(phi1 - phi0);
d1297 2
a1299 2
 
         /* Check for a solution. */
d1301 1
a1301 1
         if (dabs < tol) {
d1307 1
a1307 1
 
@


2.19
log
@Fixed two bugs in the translation from NCP to SIN in wcsfwd() and wcsrev():
(1) the projection parameter was computed incorrectly and (2) they did not
honour prj->flag set to -1 to disable strict bounds checking; fixed a bug in
wcsmix() - it was relying on the wcsprm struct to have been initialized
beforehand.
@
text
@d4 1
a4 1
*   Copyright (C) 1995-2000, Mark Calabretta
d222 6
a227 1
*                        degrees.
d385 1
a385 1
*   $Id: wcs.c,v 2.18 2000/12/05 03:43:53 mcalabre Exp mcalabre $
@


2.18
log
@Recognize GLS as a synonym for SFL; recognize 'xyLN/xyLT' axis pairs;
reordered projections to match paper.
@
text
@d380 1
a380 1
*   $Id: wcs.c,v 2.17 2000/09/07 22:49:26 mcalabre Exp mcalabre $
d584 1
a584 1
         if (cel->ref[2] == 0.0) {
d590 2
a591 2
         prj->p[2] = cosd(cel->ref[2])/sind(cel->ref[2]);
         prj->flag = 0;
d718 1
a718 1
         if (cel->ref[2] == 0.0) {
d724 2
a725 2
         prj->p[2] = cosd(cel->ref[2])/sind(cel->ref[2]);
         prj->flag = 0;
d768 5
@


2.17
log
@Added a reference to note 2 in the description of the crval arguments.
@
text
@d293 3
a295 1
*    4) The quadcube projections (CSC, QSC, TSC) may be represented in FITS in
d380 1
a380 1
*   $Id: wcs.c,v 2.16 2000/05/10 04:44:05 mcalabre Exp mcalabre $
d431 3
d462 9
a470 2
         /* Allow NCP to pass (will be converted to SIN later). */
         if (strncmp(&ctype[j][5], "NCP", 3)) continue;
d501 12
d533 5
a1182 2
   cel0.prjfwd = cel->prjfwd;
   cel0.prjrev = cel->prjrev;
@


2.16
log
@Updated date in copyright notice.
@
text
@d97 1
a97 1
*                        CRVALn header cards.
d172 1
a172 1
*                        CRVALn header cards.
d243 1
a243 1
*                        CRVALn header cards.
d378 1
a378 1
*   $Id: wcs.c,v 2.15 2000/04/04 03:41:37 mcalabre Exp mcalabre $
@


2.15
log
@Need to include sph.h, string.h and stdio.h.
@
text
@d4 1
a4 1
*   Copyright (C) 1995-1999, Mark Calabretta
d378 1
a378 1
*   $Id: wcs.c,v 2.14 1999/12/14 01:09:28 mcalabre Exp mcalabre $
@


2.14
log
@Modified prologue comments for generalized cubeface layout.
@
text
@d378 1
a378 1
*   $Id: wcs.c,v 2.13 1999/12/13 07:37:56 mcalabre Exp mcalabre $
d382 2
d386 1
@


2.13
log
@Revised include file handling.
@
text
@d296 2
a297 2
*          a) The six faces may be concatenated in one plane in the "lazy T"
*             configuration numbered as follows:
d301 1
a301 1
*                              4  3  2  1
d305 4
d378 1
a378 1
*   $Id: wcs.c,v 2.12 1999/11/19 00:51:18 mcalabre Exp mcalabre $
@


2.12
log
@Fixed definition of the signbit() macro; further fix for CUBEFACE handling
in wcsfwd().
@
text
@d374 1
a374 1
*   $Id: wcs.c,v 2.11 1998/07/20 04:09:19 mcalabre Exp mcalabre $
d377 1
d379 1
@


2.11
log
@Fixed cube face handling.
@
text
@d4 1
a4 1
*   Copyright (C) 1995-1998, Mark Calabretta
d374 1
a374 1
*   $Id: wcs.c,v 2.10 1998/02/25 07:05:50 mcalabre Exp mcalabre $
d409 1
a409 1
#define signbit(X) ((X) < 0.0 ? 0 : 1)
d584 1
a584 1
            imgcrd[wcs->lng] += offset;
@


2.10
log
@Updated date in copyright notice.
@
text
@d374 1
a374 1
*   $Id: wcs.c,v 2.9 1998/02/25 06:36:55 mcalabre Exp mcalabre $
d565 1
a565 1
            offset = 45.0;
d567 1
a567 1
            offset = prj->r0*PI/4.0;
d571 1
a571 1
         if (imgcrd[wcs->lat] < offset) {
d574 5
a578 2
         } else if (imgcrd[wcs->lng] < offset*3) {
            imgcrd[wcs->lng] += offset*3;
d580 2
a581 2
         } else if (imgcrd[wcs->lng] < offset*2) {
            imgcrd[wcs->lng] += offset*2;
d583 1
a583 1
         } else if (imgcrd[wcs->lng] < offset) {
a585 3
         } else if (imgcrd[wcs->lat] > offset) {
            imgcrd[wcs->lat] -= offset;
            imgcrd[wcs->cubeface] = 0.0;
d648 1
a648 1
            offset = 45.0;
d650 1
a650 1
            offset = prj->r0*PI/4.0;
d661 1
a661 1
            imgcrd[wcs->lng] -= offset;
d664 1
a664 1
            imgcrd[wcs->lng] -= offset*2;
d667 1
a667 1
            imgcrd[wcs->lng] -= offset*3;
@


2.9
log
@Fixed the problem in wcsmix() where it failed to find a valid solution when
the solution point lay at a native pole of a projection in which the pole is
represented as a finite interval.  However, wcsmix() will only ever return
one solution even when two or more valid solutions may exist.

wcsmix() now accepts viter in the range 5 - 10, the specified value will be
pushed up or down into this range if necessary.
@
text
@d4 1
a4 1
*   Copyright (C) 1995-1997 Mark Calabretta
d374 1
a374 1
*   $Id: wcs.c,v 2.8 1998/01/30 00:26:02 mcalabre Exp mcalabre $
@


2.8
log
@Fixed a prologue comment for wcsmix().
@
text
@d231 1
a231 1
*                        range is 0 - 5.
d363 4
a366 5
*      Note that there is a circumstance where the problem posed to wcsmix()
*      is ill-conditioned and it may fail to find a valid solution where one
*      does exist.  This may arise when the solution point lies at a native
*      pole of a projection in which the pole is represented as a finite
*      interval.
d374 1
a374 1
*   $Id: wcs.c,v 2.7 1997/02/19 03:22:04 mcalabre Exp mcalabre $
d720 1
a720 1
   int    crossed, err, istep, iter, retry;
d728 2
d749 5
a753 4
   if (viter < 0) {
      viter = 0;
   } else if (viter > 5) {
      viter = 5;
d760 1
a760 1
   for (istep = 0; istep <= viter; istep++) {
d1132 120
@


2.7
log
@Recognize the NCP projection and convert it to the equivalent SIN
projection.
@
text
@d218 2
a219 2
*                              world[wcs->lng], longitude returned in
*                              world[wcs->lat].
d375 1
a375 1
*   $Id: wcs.c,v 2.6 1997/01/02 22:09:49 mcalabre Exp mcalabre $
@


2.6
log
@Added extra prologue comments to explain the two representations of the
quadcube projections.  Include wcsmath.h before proj.h for mathematical
constants.
@
text
@d4 1
a4 1
*   Copyright (C) 1995,1996 Mark Calabretta
d290 4
a293 1
*    3) The quadcube projections (CSC, QSC, TSC) may be represented in FITS in
d375 1
a375 1
*   $Id: wcs.c,v 2.5 1996/09/10 06:37:10 mcalabre Exp mcalabre $
d448 4
a451 1
      if (k == npcode) continue;
d545 12
d679 12
@


2.5
log
@* Replaced usage of nint() which is not very portable.
* Replaced one erroneous usage of abs() with fabs().
@
text
@d290 2
d293 20
d372 1
a372 1
*   $Id: wcs.c,v 2.4 1996/05/24 07:25:36 mcalabre Exp mcalabre $
d375 1
@


2.4
log
@Include wcs.h earlier to handle const definition for K&R compiler.
@
text
@d350 1
a350 1
*   $Id: wcs.c,v 2.3 1996/05/07 20:10:15 mcalabre Exp mcalabre $
d601 2
a602 2
         face = nint(imgcrd[wcs->cubeface]);
         if (abs(imgcrd[wcs->cubeface]-face) > 1e-10) {
@


2.3
log
@Added const-correctness to function arguments.
Implemented the CUBEFACE axis for quadcube projections.
Added external arrays of error messages indexed by function return value.
@
text
@d350 1
a350 1
*   $Id: wcs.c,v 2.2 1995/11/16 04:48:51 mcalabre Exp mcalabre $
d353 2
a381 9

#include "wcs.h"


#ifndef __STDC__
#ifndef const
#define const
#endif
#endif
@


2.2
log
@Added wcsset() and generalized wcsfwd(), wcsrev(), and wcsmix() to handle
the CTYPEn and CRVALn FITS header cards and the non-celestial (linear)
coordinate axes.
@
text
@d4 1
a4 1
*   Copyright (C) 1995, Mark Calabretta
d56 5
a60 2
*      naxis    int      Number of image axes.
*      ctype[][9] char   Coordinate axis types corresponding to the FITS
d79 3
a81 1
*      ctype[][9] char   Coordinate axis types corresponding to the FITS
d89 2
a90 1
*      world    double[] World coordinates.  world[wcs->lng] and
d95 2
a96 1
*      crval    double[] Coordinate reference values corresponding to the FITS
d114 3
a116 1
*                        y-coordinates, in "degrees".
d139 3
a141 1
*      ctype[][9] char   Coordinate axis types corresponding to the FITS
d149 2
a150 1
*      pixcrd   double[] Pixel coordinate.
d170 2
a171 1
*      crval    double[] Coordinate reference values corresponding to the FITS
d199 3
a201 1
*      ctype[][9] char   Coordinate axis types corresponding to the FITS
d209 4
a212 2
*      mixpix   int      Which element of the pixel coordinate is given.
*      mixcel   int      Which element of the celestial coordinate is
d220 2
a221 1
*      vspan[2] double   Solution interval for the celestial coordinate, in
d223 2
a224 1
*      vstep    double   Step size for solution search, in degrees.  If zero,
d227 2
a228 1
*      viter    int      If a solution is not found then the step size will be
d241 2
a242 1
*      crval    double[] Coordinate reference values corresponding to the FITS
d314 5
d350 1
a350 1
*   $Id: wcs.c,v 2.1 1995/11/09 03:29:00 mcalabre Exp mcalabre $
d353 28
d383 1
d397 2
a398 2
int  naxis;
char ctype[][9];
d407 3
a409 2
   wcs->lng = 0;
   wcs->lat = 0;
d412 11
a422 1
      if (ctype[j][4] != '-') continue;
d494 1
a494 1
char   ctype[][9];
d496 2
a497 1
double world[], crval[];
d507 1
d527 30
d572 1
a572 1
char   ctype[][9];
d574 1
a574 1
double pixcrd[];
d579 1
a579 1
double crval[];
d584 2
a585 1
   int    err, j;
d604 1
d606 38
d659 1
a659 1
char   ctype[][9];
d661 5
a665 4
int    mixpix, mixcel;
double vspan[2], vstep;
int    viter;
double world[], crval[];
@


2.1
log
@Clarified the description of WCSMIX and some other prologue comments.
The initialization loop for imgcrd[] in wcsfwd() was missing a ";" and
this changed its meaning.  wcsmix() returns exit status 5 if no solution
is found.
@
text
@d39 3
a41 2
*   Given an element of (lng,lat) and of a pixel coordinate a hybrid routine,
*   wcsmix(), iteratively solves for the unknown elements.
d43 3
d47 24
d73 14
a86 1
*   Compute the pixel coordinate for given celestial coordinates (lng,lat).
d89 2
a90 2
*      pcode[4] char     WCS projection code (see below).
*      lng,lat  double   Celestial longitude and latitude, in degrees.
d93 2
a94 2
*      cel      celprm*  Spherical coordinate transformation parameters
*                        (usage is described in the prologue to "cel.c").
d105 2
a106 2
*      imgcrd   double[] Image coordinate.  The first two elements of this
*                        vector are assumed to be the projected x-, and
d121 1
a121 1
*                           3: Invalid value of (lng,lat).
d124 1
d127 9
a135 1
*   Compute the celestial coordinates (lng,lat) for a given pixel coordinate.
a137 1
*      pcode[4] char     WCS projection code (see below).
d145 2
a146 2
*      imgcrd   double[] Image coordinate.  The first two elements of this
*                        vector are assumed to be the projected x-, and
d157 4
d166 3
a168 1
*      lng,lat  double*  Celestial longitude and latitude, in degrees.
d175 1
a175 1
*                           3: Invalid value of (lng,lat).
d178 1
d181 3
a183 3
*   Given an element of (lng,lat) and of a pixel coordinate solve for the
*   remaining elements by iterating on the unknown celestial coordinate
*   element using wcsfwd().
d186 17
a202 9
*      pcode[4] char     WCS projection code (see below).
*      mix      int      The absolute value indicates which element of the
*                        pixel coordinate (pixcrd) is given (counting from 1),
*                        and the sign indicates which element of the celestial
*                        coordinate is given:
*                           mix < 0: celestial longitude is given,
*                                    latitude returned.
*                           mix > 0: celestial latitude is given,
*                                    longitude returned.
d213 10
a222 4
*   Given or returned:
*      lng,lat  double*  Celestial longitude and latitude, in degrees.  Which
*                        is given and which returned depends on the value of
*                        'mix'.
d237 3
a239 3
*      imgcrd   double[] Image coordinate.  It is assumed that the projected
*                        x-, and y-coordinates are the first two elements of
*                        this vector.
d246 1
a246 1
*      pixcrd   double[] Pixel coordinate.  The element indicated by mix is
d258 38
a295 1
*   Algorithm:
a322 41
*   WCS projection codes
*   --------------------
*   Zenithals/azimuthals:
*      AZP: zenithal/azimuthal perspective
*      TAN: gnomonic
*      SIN: synthesis (generalized orthographic)
*      STG: stereographic
*      ARC: zenithal/azimuthal equidistant
*      ZPN: zenithal/azimuthal polynomial
*      ZEA: zenithal/azimuthal equal area
*      AIR: Airy
*
*   Cylindricals:
*      CYP: cylindrical perspective
*      CAR: Cartesian
*      MER: Mercator
*      CEA: cylindrical equal area
*
*   Conics:
*      COP: conic perspective
*      COD: conic equidistant
*      COE: conic equal area
*      COO: conic orthomorphic
*
*   Polyconics:
*      BON: Bonne
*      PCO: polyconic
*
*   Pseudo-cylindricals:
*      GLS: Sanson-Flamsteed (global sinusoidal)
*      PAR: parabolic
*      MOL: Mollweide
*
*   Conventional:
*      AIT: Hammer-Aitoff
*
*   Quad-cubes:
*      CSC: COBE quadrilateralized spherical cube
*      QSC: quadrilateralized spherical cube
*      TSC: tangential spherical cube
*
d324 1
a324 1
*   $Id: wcs.c,v 2.0 1995/09/11 08:44:44 mcalabre Exp mcalabre $
d340 87
a426 1
int wcsfwd(pcode, lng, lat, cel, phi, theta, prj, imgcrd, lin, pixcrd)
d428 3
a430 2
char   pcode[4];
double lng, lat;
d441 10
a450 4
   /* Compute projected coordinates. */
   if (err = celfwd(pcode, lng, lat, cel, theta, phi, prj,
                    &imgcrd[0], &imgcrd[1])) {
      return err;
d453 7
a459 1
   for (j = 2; j < lin->naxis; imgcrd[j++] = 0.0);
d471 2
a472 1
int wcsrev(pcode, pixcrd, lin, imgcrd, prj, phi, theta, cel, lng, lat)
d474 2
a475 1
char   pcode[4];
d481 1
d483 1
a483 1
double *lng, *lat;
d486 1
a486 1
   int    err;
d488 5
d498 13
a510 4
   /* Compute projected coordinates. */
   if (err = celrev(pcode, imgcrd[0], imgcrd[1], prj, phi, theta, cel,
                    lng, lat)) {
      return err;
d518 2
a519 2
int wcsmix(pcode, mix, vspan, vstep, viter, lng, lat, cel, phi, theta, prj, 
           imgcrd, lin, pixcrd)
d521 3
a523 2
char   pcode[4];
int    mix;
d526 1
a526 1
double *lng, *lat;
d536 1
a536 1
   int    crossed, err, istep, iter, nix, retry;
d539 3
a541 3
   double pixnix;
   double lng0, lng0m, lng1, lng1m;
   double lat0, lat0m, lat1, lat1m;
d570 1
a570 2
   nix = abs(mix) - 1;
   pixnix = pixcrd[nix];
d577 1
a577 1
      if (mix < 0) {
d582 3
a584 2
         if (err = wcsfwd(pcode, *lng, lat0, cel, phi, theta, prj, imgcrd,
                          lin, pixcrd)) {
d587 1
a587 1
         d0 = pixcrd[nix] - pixnix;
d590 1
a590 4
         if (dabs < tol) {
            *lat = lat0;
            return 0;
         }
d593 3
a595 2
         if (err = wcsfwd(pcode, *lng, lat1, cel, phi, theta, prj, imgcrd,
                          lin, pixcrd)) {
d598 1
a598 1
         d1 = pixcrd[nix] - pixnix;
d601 2
a602 4
         if (dabs < tol) {
            *lat = lat1;
            return 0;
         }
d620 3
a622 2
               if (err = wcsfwd(pcode, *lng, lat0, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d625 1
a625 1
               d0 = pixcrd[nix] - pixnix;
d629 1
a629 4
               if (dabs < tol) {
                  *lat = lat0;
                  return 0;
               }
d660 4
a663 3
                  *lat = lat0 + lambda*(lat1 - lat0);
                  if (err = wcsfwd(pcode, *lng, *lat, cel, phi, theta, prj,
                                   imgcrd, lin, pixcrd)) {
d666 1
a666 1
                  d = pixcrd[nix] - pixnix;
d674 1
a674 1
                     lmin = *lat;
d679 1
a679 1
                     lat0 = *lat;
d682 1
a682 1
                     lat1 = *lat;
d698 2
a699 2
               *lat = lmin;
               lat0 = *lat - step;
d701 1
a701 1
               lat1 = *lat + step;
d704 3
a706 2
               if (err = wcsfwd(pcode, *lng, lat0, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d709 1
a709 1
               d0 = fabs(pixcrd[nix] - pixnix);
d712 4
a715 2
               if (err = wcsfwd(pcode, *lng, lat1, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d718 1
a718 1
               d1 = fabs(pixcrd[nix] - pixnix);
d721 4
a724 3
                  lat0m = (lat0 + *lat)/2.0;
                  if (err = wcsfwd(pcode, *lng, lat0m, cel, phi, theta, prj,
                                   imgcrd, lin, pixcrd)) {
d727 3
a729 5
                  d0m = fabs(pixcrd[nix] - pixnix);
                  if (d0m < tol) {
                     *lat = lat0m;
                     return 0;
                  }
d731 4
a734 3
                  lat1m = (lat1 + *lat)/2.0;
                  if (err = wcsfwd(pcode, *lng, lat1m, cel, phi, theta, prj,
                                   imgcrd, lin, pixcrd)) {
d737 3
a739 5
                  d1m = fabs(pixcrd[nix] - pixnix);
                  if (d1m < tol) {
                     *lat = lat1m;
                     return 0;
                  }
d742 1
a742 1
                     lat1 = *lat;
d744 1
a744 1
                     *lat = lat0m;
d747 1
a747 1
                     lat0 = *lat;
d749 1
a749 1
                     *lat = lat1m;
d766 3
a768 2
         if (err = wcsfwd(pcode, lng0, *lat, cel, phi, theta, prj, imgcrd,
                          lin, pixcrd)) {
d771 1
a771 1
         d0 = pixcrd[nix] - pixnix;
d774 1
a774 4
         if (dabs < tol) {
            *lng = lng0;
            return 0;
         }
d777 3
a779 2
         if (err = wcsfwd(pcode, lng1, *lat, cel, phi, theta, prj, imgcrd,
                          lin, pixcrd)) {
d782 1
a782 1
         d1 = pixcrd[nix] - pixnix;
d785 1
a785 4
         if (dabs < tol) {
            *lng = lng1;
            return 0;
         }
d803 3
a805 2
               if (err = wcsfwd(pcode, lng0, *lat, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d808 1
a808 1
               d0 = pixcrd[nix] - pixnix;
d812 1
a812 4
               if (dabs < tol) {
                  *lng = lng0;
                  return 0;
               }
d843 4
a846 3
                  *lng = lng0 + lambda*(lng1 - lng0);
                  if (err = wcsfwd(pcode, *lng, *lat, cel, phi, theta, prj,
                                   imgcrd, lin, pixcrd)) {
d849 1
a849 1
                  d = pixcrd[nix] - pixnix;
d857 1
a857 1
                     lmin = *lng;
d862 1
a862 1
                     lng0 = *lng;
d865 1
a865 1
                     lng1 = *lng;
d881 2
a882 2
               *lng = lmin;
               lng0 = *lng - step;
d884 1
a884 1
               lng1 = *lng + step;
d887 3
a889 2
               if (err = wcsfwd(pcode, lng0, *lat, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d892 2
a893 1
               d0 = fabs(pixcrd[nix] - pixnix);
d895 4
a898 2
               if (err = wcsfwd(pcode, lng1, *lat, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d901 1
a901 1
               d1 = fabs(pixcrd[nix] - pixnix);
d904 4
a907 3
                  lng0m = (lng0 + *lng)/2.0;
                  if (err = wcsfwd(pcode, lng0m, *lat, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d910 3
a912 5
                  d0m = fabs(pixcrd[nix] - pixnix);
                  if (d0m < tol) {
                     *lng = lng0m;
                     return 0;
                  }
d914 4
a917 3
                  lng1m = (lng1 + *lng)/2.0;
                  if (err = wcsfwd(pcode, lng1m, *lat, cel, phi, theta, prj,
                                imgcrd, lin, pixcrd)) {
d920 3
a922 5
                  d1m = fabs(pixcrd[nix] - pixnix);
                  if (d1m < tol) {
                     *lng = lng1m;
                     return 0;
                  }
d925 1
a925 1
                     lng1 = *lng;
d927 1
a927 1
                     *lng = lng0m;
d930 1
a930 1
                     lng0 = *lng;
d932 1
a932 1
                     *lng = lng1m;
@


2.0
log
@WCSLIB 2.0
@
text
@d35 1
a35 1
*   wcsfwd() and wcsrev() are high level driver routine for the WCS linear
d39 2
a40 2
*   Given an element of (lng,lat) and of (x,y) a hybrid routine, wcsmix(),
*   iteratively solves for the two unknown elements.
d45 1
a45 1
*   Compute pixel coordinate for given celestial coordinates (lng,lat).
d126 2
a127 1
*   unknowns by iterating on the unknown celestial coordinate element.
d258 1
a258 1
*   $Id: wcs.c,v 1.2 1995/09/11 04:38:08 mcalabre Exp mcalabre $
d294 1
a294 1
   for (j = 2; j < lin->naxis; imgcrd[j++] = 0.0)
d771 1
a771 1
   return 4;
@


1.2
log
@New high level driver routines, the older drivers were renamed to celset(),
celfwd(), and celrev() (in cel.c).
@
text
@d257 1
a257 1
*   $Id: wcs.c,v 1.1 1995/01/31 03:20:27 mcalabre Exp mcalabre $
@


1.1
log
@Initial revision
@
text
@d35 3
a37 11
*   These routines are provided as drivers for the lower level spherical
*   coordinate transformation and projection routines.  There are separate
*   driver routines for the forward (wcsfwd) and reverse (wcsrev)
*   transformations.  A third routine (wcsset) initializes transformation
*   parameters but need not be called explicitly - see the explanation of
*   wcs.flag below.
*
*   Forward transformation; wcsfwd
*   ------------------------------
*   Compute (x,y) coordinates in the plane of projection from celestial
*   coordinates (lng,lat).
d39 48
d88 11
a98 3
*      pcode[4] char     WCS projection code (see below)
*      lng,lat  double   Celestial longitude and latitude of the projected
*                        point, in degrees.
a100 2
*      wcs      wcsprm*  Spherical coordinate transformation parameters
*                        (see below)
d105 2
a106 1
*      x,y      double*  Projected coordinates, "degrees".
d108 7
d121 1
d123 4
a126 4
*   Reverse transformation; wcsrev
*   ------------------------------
*   Compute the celestial coordinates (lng,lat) of the point with projected
*   coordinates (x,y).
d129 27
a155 2
*      pcode[4] char     WCS projection code.
*      x,y      double   Projected coordinates, "degrees".
d157 4
a161 1
*      wcs      wcsprm*  Coordinate transformation parameters (see below)
d166 11
a176 2
*      lng,lat  double*  Celestial longitude and latitude of the projected
*                        point, in degrees.
d183 31
a213 1
*                           3: Invalid value of (x,y).
a255 28
*   Coordinate transformation parameters; wcs
*   -----------------------------------------
*   The wcsprm struct consists of the following:
*
*      wcs.ref[3]
*         The first pair of values should be set to the celestial longitude
*         and latitude (usually right ascension and declination) of the
*         reference point of the projection.  The third value is the native
*         longitude of the pole of the celestial coordinate system which
*         corresponds to the FITS keyword LONGPOLE.  Note that this has no
*         default value and should normally be set to 180 degrees.
*      wcs.flag
*         This flag must be set to zero whenever any of wcs.ref[3] are set or
*         changed.  This signals the initialization routine (wcsset) to
*         recompute intermediaries.
*
*   The remaining members of the wcsprm struct are maintained by the
*   initialization routines and should not be modified.  This is done for the
*   sake of efficiency and to allow an arbitrary number of contexts to be
*   maintained simultaneously.
*
*      wcs.euler[6]
*         Euler angles and associated intermediaries derived from the
*         coordinate reference values.
*      wcs.prjfwd
*      wcs.prjrev
*         Pointers to the forward and reverse projection routines.
*
d257 1
a257 1
*   $Id$
d262 12
a273 1
int wcsset(pcode, wcs)
d275 8
a282 2
char pcode[4];
struct wcsprm *wcs;
d285 1
a285 2
   int    iref;
   double cphip, slat0, x, y;
d287 4
a290 104
   /* Set pointers to the forward and reverse projection routines. */
   if (strcmp(pcode, "AZP") == 0) {
      wcs->prjfwd = azpfwd;
      wcs->prjrev = azprev;
      iref = 0;
   } else if (strcmp(pcode, "TAN") == 0) {
      wcs->prjfwd = tanfwd;
      wcs->prjrev = tanrev;
      iref = 0;
   } else if (strcmp(pcode, "SIN") == 0) {
      wcs->prjfwd = sinfwd;
      wcs->prjrev = sinrev;
      iref = 0;
   } else if (strcmp(pcode, "STG") == 0) {
      wcs->prjfwd = stgfwd;
      wcs->prjrev = stgrev;
      iref = 0;
   } else if (strcmp(pcode, "ARC") == 0) {
      wcs->prjfwd = arcfwd;
      wcs->prjrev = arcrev;
      iref = 0;
   } else if (strcmp(pcode, "ZPN") == 0) {
      wcs->prjfwd = zpnfwd;
      wcs->prjrev = zpnrev;
      iref = 0;
   } else if (strcmp(pcode, "ZEA") == 0) {
      wcs->prjfwd = zeafwd;
      wcs->prjrev = zearev;
      iref = 0;
   } else if (strcmp(pcode, "AIR") == 0) {
      wcs->prjfwd = airfwd;
      wcs->prjrev = airrev;
      iref = 0;
   } else if (strcmp(pcode, "CYP") == 0) {
      wcs->prjfwd = cypfwd;
      wcs->prjrev = cyprev;
      iref = 1;
   } else if (strcmp(pcode, "CAR") == 0) {
      wcs->prjfwd = carfwd;
      wcs->prjrev = carrev;
      iref = 1;
   } else if (strcmp(pcode, "MER") == 0) {
      wcs->prjfwd = merfwd;
      wcs->prjrev = merrev;
      iref = 1;
   } else if (strcmp(pcode, "CEA") == 0) {
      wcs->prjfwd = ceafwd;
      wcs->prjrev = cearev;
      iref = 1;
   } else if (strcmp(pcode, "COP") == 0) {
      wcs->prjfwd = copfwd;
      wcs->prjrev = coprev;
      iref = 0;
   } else if (strcmp(pcode, "COD") == 0) {
      wcs->prjfwd = codfwd;
      wcs->prjrev = codrev;
      iref = 0;
   } else if (strcmp(pcode, "COE") == 0) {
      wcs->prjfwd = coefwd;
      wcs->prjrev = coerev;
      iref = 0;
   } else if (strcmp(pcode, "COO") == 0) {
      wcs->prjfwd = coofwd;
      wcs->prjrev = coorev;
      iref = 0;
   } else if (strcmp(pcode, "BON") == 0) {
      wcs->prjfwd = bonfwd;
      wcs->prjrev = bonrev;
      iref = 1;
   } else if (strcmp(pcode, "PCO") == 0) {
      wcs->prjfwd = pcofwd;
      wcs->prjrev = pcorev;
      iref = 1;
   } else if (strcmp(pcode, "GLS") == 0) {
      wcs->prjfwd = glsfwd;
      wcs->prjrev = glsrev;
      iref = 1;
   } else if (strcmp(pcode, "PAR") == 0) {
      wcs->prjfwd = parfwd;
      wcs->prjrev = parrev;
      iref = 1;
   } else if (strcmp(pcode, "AIT") == 0) {
      wcs->prjfwd = aitfwd;
      wcs->prjrev = aitrev;
      iref = 1;
   } else if (strcmp(pcode, "MOL") == 0) {
      wcs->prjfwd = molfwd;
      wcs->prjrev = molrev;
      iref = 1;
   } else if (strcmp(pcode, "CSC") == 0) {
      wcs->prjfwd = cscfwd;
      wcs->prjrev = cscrev;
      iref = 1;
   } else if (strcmp(pcode, "QSC") == 0) {
      wcs->prjfwd = qscfwd;
      wcs->prjrev = qscrev;
      iref = 1;
   } else if (strcmp(pcode, "TSC") == 0) {
      wcs->prjfwd = tscfwd;
      wcs->prjrev = tscrev;
      iref = 1;
   } else {
      /* Unrecognized projection code. */
      return 1;
d293 1
a293 21
   /* Compute celestial coordinates of the native pole. */
   if (iref == 0) {
      /* Reference point is at the native pole. */
      wcs->euler[0] = wcs->ref[0];
      wcs->euler[1] = 90.0 - wcs->ref[1];
   } else {
      /* Reference point is at the native origin. */
      slat0 = sind(wcs->ref[1]);
      cphip = cosd(wcs->ref[2]);
      if (cphip == 0.0) {
         if (slat0 != 0.0) {
            return 1;
         }
         wcs->euler[1] = 90.0;
      } else {
         if (fabs(slat0/cphip) > 1.0) {
            return 1;
         }
         wcs->euler[1] = asind(slat0/cphip);
         if (wcs->euler[1] < 0.0) wcs->euler[1] += 180.0;
      }
d295 3
a297 11
      x = -cphip*cosd(wcs->euler[1]);
      y =  sind(wcs->ref[2]);
      if (x == 0.0 && y == 0.0) {
         if (fmod(wcs->ref[2],360.0) == 0.0) {
            wcs->euler[0] = wcs->ref[0] - 90.0;
         } else {
            wcs->euler[0] = wcs->ref[0] + 90.0;
         }
      } else {
         wcs->euler[0] = wcs->ref[0] - atan2d(y,x);
      }
a298 5
   wcs->euler[2] = wcs->ref[2];
   wcs->euler[3] = cosd(wcs->euler[1]);
   wcs->euler[4] = sind(wcs->euler[1]);
   wcs->euler[5] = wcs->euler[2] - wcs->euler[0];
   wcs->flag = WCSSET;
d305 1
a305 1
int wcsfwd(pcode, lng, lat, wcs, prj, x, y)
d308 3
a310 2
double lng, lat;
struct wcsprm *wcs;
d312 3
a314 1
double *x, *y;
a317 1
   double phi, theta;
d319 3
a321 2
   if (wcs->flag == 0) {
      if (wcsset(pcode, wcs)) return 1;
d324 4
a327 6
   /* Compute native coordinates. */
   sphfwd(lng, lat, wcs->euler, &phi, &theta);

   /* Apply forward projection. */
   if (err = wcs->prjfwd(phi, theta, prj, x, y)) {
      return err == 1 ? 2 : 3;
d335 2
a336 1
int wcsrev(pcode, x, y, prj, wcs, lng, lat)
d339 6
a344 1
double x, y;
d346 3
a348 2
struct wcsprm *wcs;
double *lng, *lat;
d351 26
a376 2
   int    err;
   double phi, theta;
d378 5
a382 2
   if (wcs->flag == 0) {
      if(wcsset(pcode, wcs)) return 1;
d385 382
a766 3
   /* Apply reverse projection. */
   if (err = wcs->prjrev(x, y, prj, &phi, &theta)) {
      return err == 1 ? 2 : 3;
d769 2
a770 2
   /* Compute native coordinates. */
   sphrev(phi, theta, wcs->euler, lng, lat);
a771 1
   return 0;
@
