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	0.0;

0.0
date	2015.04.05.09.14.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.0.1.2;

5.0.1.2
date	2015.04.07.08.45.17;	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.07.23.28.21;	author mcalabre;	state Exp;
branches;
next	5.1.1.3;

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

5.1.1.4
date	2015.04.13.09.35.41;	author mcalabre;	state Exp;
branches;
next	5.1.1.5;

5.1.1.5
date	2015.04.13.13.23.46;	author mcalabre;	state Exp;
branches;
next	5.1.1.6;

5.1.1.6
date	2015.04.13.14.40.20;	author mcalabre;	state Exp;
branches;
next	5.1.1.7;

5.1.1.7
date	2015.04.15.01.44.40;	author mcalabre;	state Exp;
branches;
next	5.1.1.8;

5.1.1.8
date	2015.04.15.09.09.25;	author mcalabre;	state Exp;
branches;
next	;

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

5.2.1.2
date	2015.04.18.07.46.19;	author mcalabre;	state Exp;
branches;
next	5.2.1.3;

5.2.1.3
date	2015.04.21.01.42.58;	author mcalabre;	state Exp;
branches;
next	5.2.1.4;

5.2.1.4
date	2015.04.21.02.36.06;	author mcalabre;	state Exp;
branches;
next	;

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

5.3.1.2
date	2015.04.21.13.49.16;	author mcalabre;	state Exp;
branches;
next	;

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

5.4.1.2
date	2015.05.01.08.24.44;	author mcalabre;	state Exp;
branches;
next	5.4.1.3;

5.4.1.3
date	2015.05.02.15.56.10;	author mcalabre;	state Exp;
branches;
next	;

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

5.5.1.2
date	2015.06.06.08.48.42;	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.08.08;	author mcalabre;	state Exp;
branches;
next	5.6.1.3;

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

5.6.1.4
date	2015.06.18.08.09.06;	author mcalabre;	state Exp;
branches;
next	5.6.1.5;

5.6.1.5
date	2015.06.21.05.59.37;	author mcalabre;	state Exp;
branches;
next	5.6.1.6;

5.6.1.6
date	2015.06.28.14.44.34;	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.03.05.42.33;	author mcalabre;	state Exp;
branches;
next	5.7.1.3;

5.7.1.3
date	2015.07.03.13.26.54;	author mcalabre;	state Exp;
branches;
next	5.7.1.4;

5.7.1.4
date	2015.07.05.08.18.09;	author mcalabre;	state Exp;
branches;
next	5.7.1.5;

5.7.1.5
date	2015.07.08.10.01.04;	author mcalabre;	state Exp;
branches;
next	;

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

5.8.1.2
date	2015.07.21.08.34.56;	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.10.1.2;

5.10.1.2
date	2015.10.18.08.58.15;	author mcalabre;	state Exp;
branches;
next	;

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

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

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

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

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

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

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

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

5.16.1.2
date	2017.09.12.13.03.32;	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.32;	author mcalabre;	state Exp;
branches;
next	5.17.1.3;

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

5.17.1.4
date	2017.12.05.21.13.08;	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.56.53;	author mcalabre;	state Exp;
branches;
next	5.18.1.3;

5.18.1.3
date	2018.07.25.00.19.49;	author mcalabre;	state Exp;
branches;
next	5.18.1.4;

5.18.1.4
date	2018.07.25.01.09.39;	author mcalabre;	state Exp;
branches;
next	5.18.1.5;

5.18.1.5
date	2018.07.25.06.18.06;	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.52.42;	author mcalabre;	state Exp;
branches;
next	;

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

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

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

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

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

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

6.2.1.5
date	2019.07.08.14.08.14;	author mcalabre;	state Exp;
branches;
next	6.2.1.6;

6.2.1.6
date	2019.07.09.08.46.04;	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.12.01.03.53.46;	author mcalabre;	state Exp;
branches;
next	6.4.1.3;

6.4.1.3
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.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	2020.09.21.08.25.53;	author mcalabre;	state Exp;
branches;
next	7.3.1.4;

7.3.1.4
date	2021.01.19.14.09.10;	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.3.1.6;

7.3.1.6
date	2021.01.29.09.29.47;	author mcalabre;	state Exp;
branches;
next	;

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

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

7.5.1.2
date	2021.04.13.09.19.46;	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.06.30.16.30.30;	author mcalabre;	state Exp;
branches;
next	7.6.1.3;

7.6.1.3
date	2021.06.30.16.43.58;	author mcalabre;	state Exp;
branches;
next	;

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

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

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

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

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

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

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

7.12.1.2
date	2022.10.06.04.17.53;	author mcalabre;	state Exp;
branches;
next	7.12.1.3;

7.12.1.3
date	2022.10.07.03.29.36;	author mcalabre;	state Exp;
branches;
next	;

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

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

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

8.0.1.2
date	2023.07.04.08.59.35;	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.43.49;	author mcalabre;	state Exp;
branches;
next	8.2.1.3;

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

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

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

8.2.1.6
date	2024.05.08.15.13.53;	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.31.08;	author mcalabre;	state Exp;
branches;
next	;

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

8.3.1.2
date	2024.07.09.08.23.44;	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.15;	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.23.54;	author mcalabre;	state Exp;
branches;
next	8.6.1.3;

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

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

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

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

8.6.1.7
date	2026.04.12.11.33.34;	author mcalabre;	state Exp;
branches;
next	8.6.1.8;

8.6.1.8
date	2026.04.21.14.13.40;	author mcalabre;	state Exp;
branches;
next	8.6.1.9;

8.6.1.9
date	2026.05.11.11.28.03;	author mcalabre;	state Exp;
branches;
next	;


desc
@Implementation of the WCSLIB distortion functions.
@


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: dis.c,v 8.6.1.9 2026/05/11 11:28:03 mcalabre Exp mcalabre $
*===========================================================================*/

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

#include "wcserr.h"
#include "wcslimits.h"
#include "wcsprintf.h"
#include "wcsutil.h"
#include "dis.h"

// Map status return value to message.
const char *dis_errmsg[] = {
  "Success",
  "Null disprm pointer passed",
  "Memory allocation failed",
  "Invalid parameter value",
  "Distort error",
  "De-distort error"};

static const int DISSET = 137;

static const int DIS_TPD        =    1;
static const int DIS_POLYNOMIAL =    2;
static const int DIS_DOTPD      = 1024;

// Internal helper functions, not for general use.
static int polyset(int j, struct disprm *dis);
static int tpdset(int j, struct disprm *dis);

static int pol2tpd(int j, struct disprm *dis);
static int tpvset(int j, struct disprm *dis);
static int sipset(int j, struct disprm *dis);
static int dssset(int j, struct disprm *dis);
static int watset(int j, struct disprm *dis);
static int cheleg(int type, int m, int n, double coeffm[], double coeffn[]);

static int dispoly(DISP2X_ARGS);
static int tpd1(DISP2X_ARGS);
static int tpd2(DISP2X_ARGS);
static int tpd3(DISP2X_ARGS);
static int tpd4(DISP2X_ARGS);
static int tpd5(DISP2X_ARGS);
static int tpd6(DISP2X_ARGS);
static int tpd7(DISP2X_ARGS);
static int tpd8(DISP2X_ARGS);
static int tpd9(DISP2X_ARGS);

// The first three iparm indices have meanings common to all distortion
// functions.  They are used by disp2x(), disx2p(), disprt(), and dishdo().
#define I_DTYPE   0	// Distortion type code.
#define I_NIPARM  1	// Full (allocated) length of iparm[].
#define I_NDPARM  2	// No. of parameters in dparm[], excl. work space.

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

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

int disndp(int ndpmax) { if (ndpmax >= 0) NDPMAX = ndpmax; return NDPMAX; }

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

int dpfill(
  struct dpkey *dp,
  const char *keyword,
  const char *field,
  int j,
  int type,
  int i,
  double f)

{
  if (keyword) {
    if (field) {
      if (j && 2 <= strlen(keyword)) {
        // Fill in the axis number from the value given.
        if (keyword[2] == '\0') {
          snprintf(dp->field, 72, "%s%d.%s", keyword, j, field);
        } else {
          // Take care not to overwrite any alternate code.
          char axno[8];
          snprintf(dp->field, 72, "%s.%s", keyword, field);
          snprintf(axno, 8, "%d", j);
          dp->field[2] = axno[0];
        }

      } else {
        snprintf(dp->field, 72, "%s.%s", keyword, field);
      }
    } else {
      strncpy(dp->field, keyword, 72);
    }
  } else if (field) {
    strncpy(dp->field, field, 72);
  }

  if (j) {
    dp->j = j;
  } else {
    // The field name must either be given or preset.
    char *cp;
    if ((cp = strpbrk(dp->field, "0123456789")) != 0x0) {
      sscanf(cp, "%d.", &(dp->j));
    }
  }

  if ((dp->type = type)) {
    dp->value.f = f;
  } else {
    dp->value.i = i;
  }

  return 0;
}

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

int dpkeyi(const struct dpkey *dp)

{
  if (dp->type != 0) {
    return (int)dp->value.f;
  }

  return dp->value.i;
}

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

double dpkeyd(const struct dpkey *dp)

{
  if (dp->type == 0) {
    return (double)dp->value.i;
  }

  return dp->value.f;
}

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

int disini(int alloc, int naxis, struct disprm *dis)

{
  return disinit(alloc, naxis, dis, -1);
}

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

int disinit(int alloc, int naxis, struct disprm *dis, int ndpmax)

{
  static const char *function = "disinit";

  // Check inputs.
  if (dis == 0x0) return DISERR_NULL_POINTER;

  if (ndpmax < 0) ndpmax = disndp(-1);


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


  // Initialize pointers.
  if (dis->flag == -1 || dis->m_flag != DISSET) {
    if (dis->flag == -1) {
      dis->docorr = 0x0;
      dis->Nhat   = 0x0;

      dis->axmap  = 0x0;
      dis->offset = 0x0;
      dis->scale  = 0x0;
      dis->iparm  = 0x0;
      dis->dparm  = 0x0;

      dis->disp2x = 0x0;
      dis->disx2p = 0x0;

      dis->i_naxis = 0;
    }

    // Initialize memory management.
    dis->m_flag   = 0;
    dis->m_naxis  = 0;
    dis->m_dtype  = 0x0;
    dis->m_dp     = 0x0;
    dis->m_maxdis = 0x0;
  }

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

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


  // Allocate memory for arrays if required.
  if (alloc ||
      dis->dtype  == 0x0 ||
      (ndpmax && dis->dp == 0x0) ||
      dis->maxdis == 0x0) {

    // Was sufficient allocated previously?
    if (dis->m_flag == DISSET &&
       (dis->m_naxis < naxis  ||
        dis->ndpmax  < ndpmax)) {
      // No, free it.
      disfree(dis);
    }

    if (alloc || dis->dtype == 0x0) {
      if (dis->m_dtype) {
        // In case the caller fiddled with it.
        dis->dtype = dis->m_dtype;

      } else {
        if ((dis->dtype = calloc(naxis, sizeof(char [72]))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_dtype = dis->dtype;
      }
    }

    if (alloc || dis->dp == 0x0) {
      if (dis->m_dp) {
        // In case the caller fiddled with it.
        dis->dp = dis->m_dp;

      } else {
        if (ndpmax) {
          if ((dis->dp = calloc(ndpmax, sizeof(struct dpkey))) == 0x0) {
            disfree(dis);
            return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
          }
        } else {
          dis->dp = 0x0;
        }

        dis->ndpmax  = ndpmax;

        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_dp    = dis->dp;
      }
    }

    if (alloc || dis->maxdis == 0x0) {
      if (dis->m_maxdis) {
        // In case the caller fiddled with it.
        dis->maxdis = dis->m_maxdis;

      } else {
        if ((dis->maxdis = calloc(naxis, sizeof(double))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_maxdis = dis->maxdis;
      }
    }
  }


  // Set defaults.
  dis->naxis = naxis;

  if (naxis) {
    memset(dis->dtype, 0, naxis*sizeof(char [72]));
  }

  dis->ndp = 0;
  if (ndpmax) {
    memset(dis->dp, 0, ndpmax*sizeof(struct dpkey));
  }

  dis->totdis = 0.0;
  if (naxis) {
    memset(dis->maxdis, 0, naxis*sizeof(double));
  }

  dis->flag = 0;

  return 0;
}


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

int discpy(int alloc, const struct disprm *dissrc, struct disprm *disdst)

{
  static const char *function = "discpy";

  if (dissrc == 0x0) return DISERR_NULL_POINTER;
  if (disdst == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(disdst->err);

  int naxis = dissrc->naxis;
  if (naxis < 1) {
    return wcserr_set(WCSERR_SET(DISERR_MEMORY),
      "naxis must be positive (got %d)", naxis);
  }

  int status;
  if ((status = disinit(alloc, naxis, disdst, dissrc->ndpmax))) {
    return status;
  }

  memcpy(disdst->dtype, dissrc->dtype, naxis*sizeof(char [72]));

  disdst->ndp = dissrc->ndp;
  if (disdst->dp) {
    memcpy(disdst->dp, dissrc->dp, dissrc->ndpmax*sizeof(struct dpkey));
  }

  disdst->totdis = dissrc->totdis;
  memcpy(disdst->maxdis, dissrc->maxdis, naxis*sizeof(double));

  return 0;
}

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

int disfree(struct disprm *dis)

{
  if (dis == 0x0) return DISERR_NULL_POINTER;

  if (dis->flag != -1) {
    // Optionally allocated by disinit() for given parameters.
    if (dis->m_flag == DISSET) {
      if (dis->dtype  == dis->m_dtype)  dis->dtype  = 0x0;
      if (dis->dp     == dis->m_dp)     dis->dp     = 0x0;
      if (dis->maxdis == dis->m_maxdis) dis->maxdis = 0x0;

      if (dis->m_dtype)  free(dis->m_dtype);
      if (dis->m_dp)     free(dis->m_dp);
      if (dis->m_maxdis) free(dis->m_maxdis);
    }

    // The remainder were allocated by disset().
    if (dis->docorr) free(dis->docorr);
    if (dis->Nhat)   free(dis->Nhat);

    // Recall that axmap, offset, and scale were allocated in bulk.
    if (dis->axmap  && dis->axmap[0])  free(dis->axmap[0]);
    if (dis->offset && dis->offset[0]) free(dis->offset[0]);
    if (dis->scale  && dis->scale[0])  free(dis->scale[0]);

    if (dis->axmap)  free((void *)dis->axmap);
    if (dis->offset) free((void *)dis->offset);
    if (dis->scale)  free((void *)dis->scale);

    if (dis->iparm) {
      for (int j = 0; j < dis->i_naxis; j++) {
        if (dis->iparm[j]) free(dis->iparm[j]);
      }
      free((void *)dis->iparm);
    }

    if (dis->dparm) {
      for (int j = 0; j < dis->i_naxis; j++) {
        if (dis->dparm[j]) free(dis->dparm[j]);
      }
      free((void *)dis->dparm);
    }

    if (dis->disp2x) free((void *)dis->disp2x);
    if (dis->disx2p) free((void *)dis->disx2p);
  }

  dis->m_flag   = 0;
  dis->m_naxis  = 0;
  dis->m_dtype  = 0x0;
  dis->m_dp     = 0x0;
  dis->m_maxdis = 0x0;

  dis->docorr = 0x0;
  dis->Nhat   = 0x0;
  dis->axmap  = 0x0;
  dis->offset = 0x0;
  dis->scale  = 0x0;
  dis->iparm  = 0x0;
  dis->dparm  = 0x0;
  dis->disp2x = 0x0;
  dis->disx2p = 0x0;

  wcserr_clear(&(dis->err));

  dis->flag = 0;

  return 0;
}

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

int dissize(const struct disprm *dis, int sizes[2])

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

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

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

  int naxis = dis->naxis;

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

  // disprm::dp[].
  sizes[1] += dis->ndpmax * (int)sizeof(struct dpkey);

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

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

  // The remaining arrays are allocated by disset().
  if (abs(dis->flag) != DISSET) {
    return 0;
  }

  // dis::docorr[].
  sizes[1] += naxis * (int)sizeof(int *);

  // dis::Nhat[].
  sizes[1] += naxis * (int)sizeof(int *);

  // dis::axmap[][].
  sizes[1] += naxis * (int)sizeof(int *);
  sizes[1] += naxis*naxis * (int)sizeof(int);

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

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

  // dis::iparm[][].
  sizes[1] += naxis * (int)sizeof(int *);
  for (int j = 0; j < naxis; j++) {
    if (dis->iparm[j]) {
      sizes[1] += dis->iparm[j][I_NIPARM] * (int)sizeof(int);
    }
  }

  // dis::dparm[][].
  sizes[1] += naxis * (int)sizeof(double *);
  for (int j = 0; j < naxis; j++) {
    if (dis->dparm[j]) {
      sizes[1] += (int)dis->dparm[j][I_NDPARM] * (int)sizeof(double);
    }
  }

  // dis::disp2x[].
  sizes[1] += naxis * (int)sizeof(int (*)(DISP2X_ARGS));

  // dis::disx2p[].
  sizes[1] += naxis * (int)sizeof(int (*)(DISX2P_ARGS));

  return 0;
}

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

int disenq(const struct disprm *dis, int enquiry)

{
  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;

  int answer = 0;

  if (enquiry & DISENQ_MEM) {
    if (dis->m_flag != DISSET) return 0;
    answer = 1;
  }

  if (enquiry & DISENQ_SET) {
    if (abs(dis->flag) != DISSET) return 0;
    answer = 1;
  }

  if (enquiry & DISENQ_BYP) {
    if (dis->flag != 1 && dis->flag != -DISSET) return 0;
    answer = 1;
  }

  return answer;
}

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

int disprt(const struct disprm *dis)

{
  if (dis == 0x0) return DISERR_NULL_POINTER;

  if (abs(dis->flag) != DISSET) {
    wcsprintf("The disprm struct is UNINITIALIZED.\n");
    return 0;
  }

  int naxis = dis->naxis;


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

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

  wcsprintf("        ndp: %d\n", dis->ndp);
  wcsprintf("     ndpmax: %d\n", dis->ndpmax);
  WCSPRINTF_PTR("         dp: ", dis->dp, "\n");
  for (int i = 0; i < dis->ndp; i++) {
    if (dis->dp[i].type) {
      wcsprintf("             %3d%3d  %#- 11.5g  %.32s\n",
        dis->dp[i].j, dis->dp[i].type, dis->dp[i].value.f, dis->dp[i].field);
    } else {
      wcsprintf("             %3d%3d  %11d  %.32s\n",
        dis->dp[i].j, dis->dp[i].type, dis->dp[i].value.i, dis->dp[i].field);
    }
  }

  wcsprintf("     totdis:  %#- 11.5g\n", dis->totdis);

  WCSPRINTF_PTR("     maxdis: ", dis->maxdis, "\n");
  wcsprintf("            ");
  for (int j = 0; j < naxis; j++) {
    wcsprintf("  %#- 11.5g", dis->maxdis[j]);
  }
  wcsprintf("\n");

  // Derived values.
  WCSPRINTF_PTR("     docorr: ", dis->docorr, "\n");
  wcsprintf("            ");
  for (int j = 0; j < naxis; j++) {
    wcsprintf("%6d", dis->docorr[j]);
  }
  wcsprintf("\n");

  WCSPRINTF_PTR("       Nhat: ", dis->Nhat, "\n");
  wcsprintf("            ");
  for (int j = 0; j < naxis; j++) {
    wcsprintf("%6d", dis->Nhat[j]);
  }
  wcsprintf("\n");

  WCSPRINTF_PTR("      axmap: ", dis->axmap, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf(" axmap[%d][]:", j);
    for (int jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("%6d", dis->axmap[j][jhat]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("     offset: ", dis->offset, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf("offset[%d][]:", j);
    for (int jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("  %#- 11.5g", dis->offset[j][jhat]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      scale: ", dis->scale, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf(" scale[%d][]:", j);
    for (int jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("  %#- 11.5g", dis->scale[j][jhat]);
    }
    wcsprintf("\n");
  }

  WCSPRINTF_PTR("      iparm: ", dis->iparm, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf(" iparm[%d]  : ", j);
    WCSPRINTF_PTR("", dis->iparm[j], "\n");

    if (dis->iparm[j]) {
      wcsprintf(" iparm[%d][]:", j);
      for (int k = 0; k < dis->iparm[j][I_NIPARM]; k++) {
        if (k && k%5 == 0) {
          wcsprintf("\n            ");
        }
        wcsprintf("  %11d", dis->iparm[j][k]);
      }
      wcsprintf("\n");
    }
  }

  WCSPRINTF_PTR("      dparm: ", dis->dparm, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf(" dparm[%d]  : ", j);
    WCSPRINTF_PTR("", dis->dparm[j], "\n");

    if (dis->dparm[j]) {
      wcsprintf(" dparm[%d][]:", j);
      for (int k = 0; k < dis->iparm[j][I_NDPARM]; k++) {
        if (k && k%5 == 0) {
          wcsprintf("\n            ");
        }
        wcsprintf("  %#- 11.5g", dis->dparm[j][k]);
      }
      wcsprintf("\n");
    }
  }

  wcsprintf("    i_naxis: %d\n", dis->i_naxis);
  wcsprintf("       ndis: %d\n", dis->ndis);

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

  // Pointers to distortion functions.
  char hext[32];
  WCSPRINTF_PTR("     disp2x: ", dis->disp2x, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf("  disp2x[%d]: %s", j,
      wcsutil_fptr2str((void (*)(void))dis->disp2x[j], hext));
    if (dis->disp2x[j] == dispoly) {
      wcsprintf("  (= dispoly)\n");
    } else if (dis->disp2x[j] == tpd1) {
      wcsprintf("  (= tpd1)\n");
    } else if (dis->disp2x[j] == tpd2) {
      wcsprintf("  (= tpd2)\n");
    } else if (dis->disp2x[j] == tpd3) {
      wcsprintf("  (= tpd3)\n");
    } else if (dis->disp2x[j] == tpd4) {
      wcsprintf("  (= tpd4)\n");
    } else if (dis->disp2x[j] == tpd5) {
      wcsprintf("  (= tpd5)\n");
    } else if (dis->disp2x[j] == tpd6) {
      wcsprintf("  (= tpd6)\n");
    } else if (dis->disp2x[j] == tpd7) {
      wcsprintf("  (= tpd7)\n");
    } else if (dis->disp2x[j] == tpd8) {
      wcsprintf("  (= tpd8)\n");
    } else if (dis->disp2x[j] == tpd9) {
      wcsprintf("  (= tpd9)\n");
    } else {
      wcsprintf("\n");
    }
  }

  // Pointers to inverse distortion functions.
  WCSPRINTF_PTR("     disx2p: ", dis->disx2p, "\n");
  for (int j = 0; j < naxis; j++) {
    wcsprintf("  disx2p[%d]: %s\n", j,
      wcsutil_fptr2str((void (*)(void))dis->disx2p[j], hext));
  }

  // Memory management.
  wcsprintf("     m_flag: %d\n", dis->m_flag);
  wcsprintf("    m_naxis: %d\n", dis->m_naxis);
  WCSPRINTF_PTR("    m_dtype: ", dis->m_dtype, "");
  if (dis->m_dtype  == dis->dtype)  wcsprintf("  (= dtype)");
  wcsprintf("\n");
  WCSPRINTF_PTR("       m_dp: ", dis->m_dp, "");
  if (dis->m_dp     == dis->dp)     wcsprintf("  (= dp)");
  wcsprintf("\n");
  WCSPRINTF_PTR("   m_maxdis: ", dis->m_maxdis, "");
  if (dis->m_maxdis == dis->maxdis) wcsprintf("  (= maxdis)");
  wcsprintf("\n");

  return 0;
}

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

int disperr(const struct disprm *dis, const char *prefix)

{
  if (dis == 0x0) return DISERR_NULL_POINTER;

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

  return 0;
}

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

int dishdo(struct disprm *dis)

{
  static const char *function = "dishdo";

  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  int status = 0;
  for (int j = 0; j < dis->naxis; j++) {
    if (dis->iparm[j][I_DTYPE]) {
      if (dis->iparm[j][I_DTYPE] == DIS_TPD) {
        // Implemented as TPD...
        if (strcmp(dis->dtype[j], "TPD") != 0) {
          // ... but isn't TPD.
          dis->iparm[j][I_DTYPE] |= DIS_DOTPD;
        }
      } else {
        // Must be a Polynomial that can't be implemented as TPD.
        status = wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Translation of %s to TPD is not possible", dis->dtype[j]);
      }
    }
  }

  return status;
}

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

int disset(struct disprm *dis)

{
  static const char *function = "disset";

  if (dis == 0x0) return DISERR_NULL_POINTER;
  if (dis->flag == -DISSET) return 0;
  struct wcserr **err = &(dis->err);

  // Do basic checks.
  if (dis->ndp < 0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "disprm::ndp is negative (%d)", dis->ndp);
  }

  int naxis = dis->naxis;
  int ndis  = 0;
  for (int j = 0; j < naxis; j++) {
    if (strlen(dis->dtype[j])) {
      ndis++;
      break;
    }
  }

  char *dpq;
  if (dis->ndp) {
    // Is it prior or sequent?
    if (dis->dp[0].field[1] == 'P') {
      dpq = "DPja";
    } else if (dis->dp[0].field[1] == 'Q') {
      dpq = "DQia";
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "disprm::dp[0].field (%s) is invalid", dis->dp[0].field);
    }

  } else {
    if (ndis) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "No DPja or DQia keywords, NAXES at least is required for each "
        "distortion");
    }

    // A Clayton's distortion.  Avert compiler warnings about possible use of
    // uninitialized variables.
    dpq = 0x0;
  }


  // Free memory allocated separately for each axis.
  for (int j = 0; j < dis->i_naxis; j++) {
    if (dis->iparm[j]) free(dis->iparm[j]);
    if (dis->dparm[j]) free(dis->dparm[j]);
    dis->iparm[j] = 0x0;
    dis->dparm[j] = 0x0;
  }

  // Allocate or reallocate memory, if necessary, for derived parameter and
  // work arrays sized according to the number of axes.
  size_t naxszt = naxis;
  if (dis->i_naxis < naxis) {
    if (dis->i_naxis) {
      free(dis->docorr);
      free(dis->Nhat);

      dis->docorr = 0x0;
      dis->Nhat   = 0x0;

      // Noting that axmap, offset, and scale are allocated in bulk.
      free(dis->axmap[0]);
      free((void *)dis->axmap);
      free(dis->offset[0]);
      free((void *)dis->offset);
      free(dis->scale[0]);
      free((void *)dis->scale);

      dis->axmap  = 0x0;
      dis->offset = 0x0;
      dis->scale  = 0x0;

      free((void *)dis->iparm);
      free((void *)dis->dparm);

      dis->iparm  = 0x0;
      dis->dparm  = 0x0;

      free((void *)dis->disp2x);
      free((void *)dis->disx2p);

      dis->disp2x = 0x0;
      dis->disx2p = 0x0;
    }

    if ((dis->docorr = calloc(naxszt, sizeof(int))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->Nhat = calloc(naxszt, sizeof(int))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    // Allocate axmap[][] in bulk and then carve it up.
    if ((dis->axmap = (int **)calloc(naxszt, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->axmap[0] = calloc(naxszt*naxszt, sizeof(int))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    for (int j = 1; j < naxis; j++) {
      dis->axmap[j] = dis->axmap[j-1] + naxis;
    }

    // Allocate offset[][] in bulk and then carve it up.
    if ((dis->offset = (double **)calloc(naxszt, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->offset[0] = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    for (int j = 1; j < naxis; j++) {
      dis->offset[j] = dis->offset[j-1] + naxis;
    }

    // Allocate scale[][] in bulk and then carve it up.
    if ((dis->scale = (double **)calloc(naxszt, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->scale[0] = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    for (int j = 1; j < naxis; j++) {
      dis->scale[j] = dis->scale[j-1] + naxis;
    }

    if ((dis->iparm = (int **)calloc(naxszt, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->dparm = (double **)calloc(naxszt, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->disp2x = (int (**)(DISP2X_ARGS))calloc(naxszt,
           sizeof(int (*)(DISP2X_ARGS)))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->disx2p = (int (**)(DISX2P_ARGS))calloc(naxszt,
           sizeof(int (*)(DISX2P_ARGS)))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    dis->i_naxis = naxis;
  }

  // Start with a clean slate.
  for (int j = 0; j < naxis; j++) {
    dis->docorr[j] = 1;
  }

  memset(dis->Nhat, 0, naxszt*sizeof(int));

  for (int jhat = 0; jhat < naxis*naxis; jhat++) {
    dis->axmap[0][jhat] = -1;
  }

  memset(dis->offset[0], 0, naxszt*naxszt*sizeof(double));

  for (int jhat = 0; jhat < naxis*naxis; jhat++) {
    dis->scale[0][jhat] = 1.0;
  }

  // polyset() etc. must look after iparm[][] and dparm[][].

  dis->i_naxis = naxis;
  dis->ndis    = 0;

  memset((void *)dis->disp2x, 0, naxis*sizeof(int (*)(DISP2X_ARGS)));
  memset((void *)dis->disx2p, 0, naxis*sizeof(int (*)(DISX2P_ARGS)));


  // Handle DPja or DQia keywords common to all distortions.
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    // Check that they're all one kind or the other.
    if (keyp->field[1] != dpq[1]) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "disprm::dp appears to contain a mix of DPja and DQia keys");
    }

    int j = keyp->j;

    if (j < 1 || naxis < j) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid axis number (%d) in %s", j, keyp->field);
    }

    char *fp;
    if ((fp = strchr(keyp->field, '.')) == 0x0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid record field name: %s", j, keyp->field);
    }
    fp++;

    // Convert to 0-relative axis number.
    j--;

    if (strcmp(fp, "DOCORR") == 0) {
      if (dpkeyi(keyp) == 0) {
        dis->docorr[j] = 0;
      }

    } else if (strcmp(fp, "NAXES") == 0) {
      int Nhat = dpkeyi(keyp);
      if (Nhat < 0 || naxis < Nhat) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid value of Nhat for %s distortion in %s: %d", dis->dtype[j],
          keyp->field, Nhat);
      }

      dis->Nhat[j] = Nhat;

    } else if (strncmp(fp, "AXIS.", 5) == 0) {
      int jhat;
      sscanf(fp+5, "%d", &jhat);
      if (jhat < 1 || naxis < jhat) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid axis in axis map for %s distortion in %s: %d",
          dis->dtype[j], keyp->field, jhat);
      }

      // N.B. axis numbers in the map are 0-relative.
      dis->axmap[j][jhat-1] = dpkeyi(keyp) - 1;

    } else if (strncmp(fp, "OFFSET.", 7) == 0) {
      int jhat;
      sscanf(fp+7, "%d", &jhat);
      dis->offset[j][jhat-1] = dpkeyd(keyp);

    } else if (strncmp(fp, "SCALE.", 6) == 0) {
      int jhat;
      sscanf(fp+6, "%d", &jhat);
      dis->scale[j][jhat-1] = dpkeyd(keyp);
    }
  }

  // Set defaults and do sanity checks on axmap[][].
  for (int j = 0; j < naxis; j++) {
    if (strlen(dis->dtype[j]) == 0) {
      // No distortion on this axis, check that there are no parameters.
      keyp = dis->dp;
      for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
        if (keyp->j == j+1) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
            "No distortion type, yet %s keyvalues are present for axis %d",
            dpq, j+1);
        }
      }

      continue;
    }

    // N.B. NAXES (Nhat) has no default value.
    if (dis->Nhat[j] <= 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "%s.NAXES was not set (or bad) for %s distortion on axis %d",
        dpq, dis->dtype[j], j+1);
    }

    // Set defaults for axmap[][].
    int Nhat = dis->Nhat[j];
    for (int jhat = 0; jhat < Nhat; jhat++) {
      if (dis->axmap[j][jhat] == -1) {
        dis->axmap[j][jhat] = jhat;
      }
    }

    // Sanity check on the length of the axis map.
    Nhat = 0;
    for (int jhat = 0; jhat < naxis; jhat++) {
      if (dis->axmap[j][jhat] != -1) Nhat = jhat+1;
    }

    if (Nhat != dis->Nhat[j]) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Mismatch in length of axis map for %s distortion on axis %d",
        dis->dtype[j], j+1);
    }

    // Check uniqueness of entries in the axis map.
    for (int jhat = 0; jhat < Nhat; jhat++) {
      for (int k = 0; k < jhat; k++) {
        if (dis->axmap[j][jhat] == dis->axmap[j][k]) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
            "Duplicated entry in axis map for %s distortion on axis %d",
            dis->dtype[j], j+1);
        }
      }
    }
  }


  // Identify the distortion functions.
  ndis = 0;
  for (int j = 0; j < naxis; j++) {
    if (strlen(dis->dtype[j]) == 0) {
      // No distortion on this axis.
      continue;
    }

    if (dis->Nhat[j] == 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Empty axis map for %s distortion on axis %d", dis->dtype[j], j+1);
    }

    // Invoke the specific setup functions for each distortion.
    int status;
    if (strcmp(dis->dtype[j], "TPD") == 0) {
      // Template Polynomial Distortion.
      if ((status = tpdset(j, dis))) {
        // (Preserve the error message set by tpdset().)
        return status;
      }

    } else if (strcmp(dis->dtype[j], "TPV") == 0) {
      // TPV "projection".
      if ((status = tpvset(j, dis))) {
        // (Preserve the error message set by tpvset().)
        return status;
      }

    } else if (strcmp(dis->dtype[j], "SIP") == 0) {
      // Simple Imaging Polynomial (SIP).
      if ((status = sipset(j, dis))) {
        // (Preserve the error message set by sipset().)
        return status;
      }

    } else if (strcmp(dis->dtype[j], "DSS") == 0) {
      // Digitized Sky Survey (DSS).
      if ((status = dssset(j, dis))) {
        // (Preserve the error message set by dssset().)
        return status;
      }

    } else if (strncmp(dis->dtype[j], "WAT", 3) == 0) {
      // WAT (TNX or ZPX "projections").
      if ((status = watset(j, dis))) {
        // (Preserve the error message set by watset().)
        return status;
      }

    } else if (strcmp(dis->dtype[j], "Polynomial")  == 0 ||
               strcmp(dis->dtype[j], "Polynomial*") == 0) {
      // General polynomial distortion.
      if ((status = polyset(j, dis))) {
        // (Preserve the error message set by polyset().)
        return status;
      }

    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized/unimplemented distortion function: %s", dis->dtype[j]);
    }

    ndis++;
  }

  dis->ndis = ndis;

  dis->flag = (dis->flag == 1) ? -DISSET : DISSET;

  return 0;
}

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

int disp2x(
  struct disprm *dis,
  const double rawcrd[],
  double discrd[])

{
  static const char *function = "disp2x";

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  int status = 0;
  if (abs(dis->flag) != DISSET) {
    if ((status = disset(dis))) return status;
  }

  int naxis = dis->naxis;

  double *tmpcrd;
  if ((tmpcrd = calloc(naxis, sizeof(double))) == 0x0) {
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
  }


  // Invoke the distortion functions for each axis.
  for (int j = 0; j < naxis; j++) {
    if (dis->disp2x[j]) {
      double *offset = dis->offset[j];
      double *scale  = dis->scale[j];

      int Nhat = dis->Nhat[j];
      for (int jhat = 0; jhat < Nhat; jhat++) {
        int axisj = dis->axmap[j][jhat];
        tmpcrd[jhat] = (rawcrd[axisj] - offset[jhat])*scale[jhat];
      }

      double dtmp;
      if ((dis->disp2x[j])(0, dis->iparm[j], dis->dparm[j], Nhat, tmpcrd,
                           &dtmp)) {
        status = wcserr_set(DIS_ERRMSG(DISERR_DISTORT));
        goto cleanup;
      }

      if (dis->docorr[j]) {
        // Distortion function computes a correction to be applied.
        discrd[j] = rawcrd[j] + dtmp;
      } else {
        // Distortion function computes corrected coordinates directly.
        discrd[j] = dtmp;
      }

    } else {
      discrd[j] = rawcrd[j];
    }
  }

cleanup:
  if (tmpcrd) free(tmpcrd);
  return status;
}

//----------------------------------------------------------------------------
// This function is intended for debugging purposes only.
// No documentation or prototype is provided in dis.h.

int disitermax(int itermax)

{
  static int ITERMAX = 30;

  if (itermax >= 0) {
    ITERMAX = itermax;
  }

  return ITERMAX;
}

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

int disx2p(
  struct disprm *dis,
  const double discrd[],
  double rawcrd[])

{
  static const char *function = "disx2p";

  const double TOL = 1.0e-13;

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  int status = 0;
  if (abs(dis->flag) != DISSET) {
    if ((status = disset(dis))) return status;
  }

  int naxis = dis->naxis;

  double *tmpmem;
  if ((tmpmem = calloc(5*(size_t)naxis, sizeof(double))) == 0x0) {
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
  }

  // Carve up working memory.
  double *tmpcrd = tmpmem;
  double *dcrd0  = tmpcrd + naxis;
  double *dcrd1  = dcrd0  + naxis;
  double *rcrd1  = dcrd1  + naxis;
  double *delta  = rcrd1  + naxis;


  // Zeroth approximation.  The assumption here and below is that the
  // distortion is small so that, to first order in the neighbourhood of
  // the solution, discrd[j] ~= a + b*rawcrd[j], i.e. independent of
  // rawcrd[i], where i != j.  This is effectively equivalent to assuming
  // that the distortion functions are separable to first order.
  // Furthermore, a is assumed to be small, and b close to unity.
  memcpy(rawcrd, discrd, naxis*sizeof(double));

  // If available, use disprm::disx2p to improve the zeroth approximation.
  for (int j = 0; j < naxis; j++) {
    if (dis->disx2p[j]) {
      double *offset = dis->offset[j];
      double *scale  = dis->scale[j];

      int Nhat = dis->Nhat[j];
      for (int jhat = 0; jhat < Nhat; jhat++) {
        int axisj = dis->axmap[j][jhat];
        tmpcrd[jhat] = (discrd[axisj] - offset[jhat])*scale[jhat];
      }

      double rtmp;
      if ((status = (dis->disx2p[j])(1, dis->iparm[j], dis->dparm[j], Nhat,
                                     tmpcrd, &rtmp))) {
        status = wcserr_set(DIS_ERRMSG(DISERR_DEDISTORT));
        goto cleanup;
      }

      if (dis->docorr[j]) {
        // Inverse distortion function computes a correction to be applied.
        rawcrd[j] = discrd[j] + rtmp;
      } else {
        // Inverse distortion function computes corrected coordinates directly.
        rawcrd[j] = rtmp;
      }
    }
  }

  // Quick return debugging hook, assumes inverse functions were defined.
  int itermax;
  if ((itermax = disitermax(-1)) == 0) {
    goto cleanup;
  }


  // Iteratively invert the (well-behaved!) distortion function.
  int convergence = 0, iter;
  for (iter = 0; iter < itermax; iter++) {
    if ((status = disp2x(dis, rawcrd, dcrd0))) {
      wcserr_set(DIS_ERRMSG(status));
      goto cleanup;
    }

    // Check for convergence.
    convergence = 1;
    for (int j = 0; j < naxis; j++) {
      delta[j] = discrd[j] - dcrd0[j];

      double dd;
      if (fabs(discrd[j]) < 1.0) {
        dd = delta[j];
      } else {
        // TOL may be below the precision achievable from floating point
        // subtraction, so switch to a fractional tolerance.
        dd = delta[j] / discrd[j];
      }

      if (TOL < fabs(dd)) {
        // No convergence yet on this axis.
        convergence = 0;
      }
    }

    if (convergence) break;

    // Determine a suitable test point for computing the gradient.
    for (int j = 0; j < naxis; j++) {
      // Constrain the displacement.
      delta[j] /= 2.0;
      if (fabs(delta[j]) < 1.0e-6) {
        if (delta[j] < 0.0) {
          delta[j] = -1.0e-6;
        } else {
          delta[j] =  1.0e-6;
        }
      } else if (1.0 < fabs(delta[j])) {
        if (delta[j] < 0.0) {
          delta[j] = -1.0;
        } else {
          delta[j] =  1.0;
        }
      }
    }

    if (iter < itermax/2) {
      // With the assumption of small distortions (as above), the gradient
      // of discrd[j] should be dominated by the partial derivative with
      // respect to rawcrd[j], and we can neglect partials with respect
      // to rawcrd[i], where i != j.  Thus only one test point is needed,
      // not one for each axis.
      for (int j = 0; j < naxis; j++) {
        rcrd1[j] = rawcrd[j] + delta[j];
      }

      // Compute discrd[] at the test point.
      if ((status = disp2x(dis, rcrd1, dcrd1))) {
        wcserr_set(DIS_ERRMSG(status));
        goto cleanup;
      }

      // Compute the next approximation.
      for (int j = 0; j < naxis; j++) {
        rawcrd[j] += (discrd[j] - dcrd0[j]) *
                        (delta[j]/(dcrd1[j] - dcrd0[j]));
      }

    } else {
      // Convergence should not take more than seven or so iterations.  As
      // it is slow, try computing the gradient in full.
      memcpy(rcrd1, rawcrd, naxis*sizeof(double));

      for (int j = 0; j < naxis; j++) {
        rcrd1[j] += delta[j];

        // Compute discrd[] at the test point.
        if ((status = disp2x(dis, rcrd1, dcrd1))) {
          wcserr_set(DIS_ERRMSG(status));
          goto cleanup;
        }

        // Compute the next approximation.
        rawcrd[j] += (discrd[j] - dcrd0[j]) *
                       (delta[j]/(dcrd1[j] - dcrd0[j]));

        rcrd1[j] -= delta[j];
      }
    }
  }


  if (!convergence) {
    double residual = 0.0;
    for (int j = 0; j < naxis; j++) {
      double dd = discrd[j] - dcrd0[j] ;
      residual += dd*dd;
    }
    residual = sqrt(residual);

    status = wcserr_set(WCSERR_SET(DISERR_DEDISTORT),
      "Convergence not achieved after %d iterations, residual %#7.2g", iter,
        residual);
    goto cleanup;
  }


cleanup:
  if (tmpmem) free(tmpmem);
  return status;
}

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

int diswarp(
  struct disprm *dis,
  const double pixblc[],
  const double pixtrc[],
  const double pixsamp[],
  int    *nsamp,
  double maxdis[],
  double *maxtot,
  double avgdis[],
  double *avgtot,
  double rmsdis[],
  double *rmstot)

{
  static const char *function = "diswarp";

  int status = 0;

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  int naxis = dis->naxis;

  if (nsamp) *nsamp = 0;
  for (int j = 0; j < naxis; j++) {
    if (maxdis) maxdis[j] = 0.0;
    if (avgdis) avgdis[j] = 0.0;
    if (rmsdis) rmsdis[j] = 0.0;
  }
  if (maxtot) *maxtot = 0.0;
  if (avgtot) *avgtot = 0.0;
  if (rmstot) *rmstot = 0.0;

  // Quick return if no distortions.
  if (dis->ndis == 0) return 0;

  double *tmpmem;
  if ((tmpmem = calloc(4*(size_t)naxis, sizeof(double))) == 0x0) {
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
  }

  // Carve up working memory.
  double *pixinc = tmpmem;
  double *pixend = pixinc + naxis;
  double *sumdis = pixend + naxis;
  double *ssqdis = sumdis + naxis;

  // Work out increments on each axis.
  for (int j = 0; j < naxis; j++) {
    double pixspan = pixtrc[j] - (pixblc ? pixblc[j] : 1.0);

    if (pixsamp == 0x0) {
      pixinc[j] = 1.0;
    } else {
      if (pixsamp[j] == 0.0) {
        pixinc[j] = 1.0;
      } else if (pixsamp[j] > 0.0) {
        pixinc[j] = pixsamp[j];
      } else if (pixsamp[j] > -1.5) {
        pixinc[j] = 2.0*pixspan;
      } else {
        pixinc[j] = pixspan / ((int)(-pixsamp[j] - 0.5));
      }
    }
  }

  // Get some more memory for coordinate vectors.
  double *pix0, *pix1;
  if ((pix0 = calloc(2*(size_t)naxis, sizeof(double))) == 0x0) {
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
  }

  pix1 = pix0 + naxis;


  // Set up the array of pixel coordinates.
  for (int j = 0; j < naxis; j++) {
    pix0[j] = pixblc ? pixblc[j] : 1.0;
    pixend[j] = pixtrc[j] + 0.5*pixinc[j];
  }

  // Initialize accumulators.
  for (int j = 0; j < naxis; j++) {
    sumdis[j] = 0.0;
    ssqdis[j] = 0.0;
  }
  double sumtot = 0.0;
  double ssqtot = 0.0;


  // Loop over N dimensions.
  int carry = 0, count = 0;
  while (carry == 0) {
    if ((status = disp2x(dis, pix0, pix1))) {
      // (Preserve the error message set by disp2x().)
      goto cleanup;
    }

    // Accumulate statistics.
    count++;

    double dssq = 0.0;
    for (int j = 0; j < naxis; j++) {
      double dpix = pix1[j] - pix0[j];
      double dpx2 = dpix*dpix;

      sumdis[j] += dpix;
      ssqdis[j] += dpx2;

      if (maxdis && (dpix = fabs(dpix)) > maxdis[j]) {
        maxdis[j] = dpix;
      }

      dssq += dpx2;
    }

    double totdis = sqrt(dssq);
    sumtot += totdis;
    ssqtot += totdis*totdis;

    if (maxtot && *maxtot < totdis) {
      *maxtot = totdis;
    }

    // Next pixel.
    for (int j = 0; j < naxis; j++) {
      pix0[j] += pixinc[j];
      if (pix0[j] < pixend[j]) {
        carry = 0;
        break;
      }

      pix0[j] = pixblc ? pixblc[j] : 1.0;
      carry = 1;
    }
  }


  // Compute the means and RMSs.
  if (nsamp) *nsamp = count;

  for (int j = 0; j < naxis; j++) {
    ssqdis[j] /= count;
    sumdis[j] /= count;
    if (avgdis) avgdis[j] = sumdis[j];
    if (rmsdis) rmsdis[j] = sqrt(ssqdis[j] - sumdis[j]*sumdis[j]);
  }

  ssqtot /= count;
  sumtot /= count;
  if (avgtot) *avgtot = sumtot;
  if (rmstot) *rmstot = sqrt(ssqtot - sumtot*sumtot);


cleanup:
  if (tmpmem) {
    free(tmpmem);
    if (pix0) free(pix0);
  }

  return status;
}

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

static int polyset(int j, struct disprm *dis)

{
  static const char *function = "polyset";

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  int naxis = dis->naxis;

  char id[32];
  snprintf(id, 32, "Polynomial on axis %d", j+1);


  // Find the number of auxiliary variables and terms.
  int K = 0;
  int M = 0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp;
    if ((fp = strchr(keyp->field, '.')) == 0x0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid field name for %s: %s", id, keyp->field);
    }
    fp++;

    if (strcmp(fp, "NAUX") == 0) {
      K = dpkeyi(keyp);
    } else if (strcmp(fp, "NTERMS") == 0) {
      M = dpkeyi(keyp);
    }
  }

  if (K < 0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Invalid number of auxiliaries (%d) for %s", K, id);
  }

  if (M <= 0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Invalid number of terms (%d) for %s", M, id);
  }

  int Nhat = dis->Nhat[j];
  int nKparm = 2*(Nhat + 1);
  int nVar   = Nhat + K;
  int nTparm = 1 + nVar;
  int ndparm = K*nKparm + M*nTparm;

// These iparm indices are specific to Polynomial.
#define I_NIDX    3	// No. of indexes in iparm[].
#define I_LENDP   4	// Full (allocated) length of dparm[].
#define I_K       5	// No. of auxiliary variables.
#define I_M       6	// No. of terms in the polynomial.
#define I_NKPARM  7	// No. of parameters used to define each auxiliary.
#define I_NTPARM  8	// No. of parameters used to define each term.
#define I_NVAR    9	// No. of independent + auxiliary variables.
#define I_MNVAR  10	// No. of powers (exponents) in the polynomial.
#define I_DPOLY  11	// dparm offset for polynomial coefficients.
#define I_DAUX   12	// dparm offset for auxiliary coefficients.
#define I_DVPOW  13	// dparm offset for integral powers of variables.
#define I_MAXPOW 14	// iparm offset for max powers.
#define I_DPOFF  15	// iparm offset for dparm offsets.
#define I_FLAGS  16	// iparm offset for flags.
#define I_IPOW   17	// iparm offset for integral powers.
#define I_NPOLY  18

  // Add extra for handling integer exponents.  See "Optimization" below.
  int niparm = I_NPOLY + (2 + 2*M)*nVar;

  // Add extra memory for temporaries.
  int lendp = ndparm + K;

  // Allocate memory for the indexes and parameter array.
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  if ((dis->dparm[j] = calloc(lendp, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  // These help a bit to stop the code from turning into hieroglyphics.
  int    *iparm = dis->iparm[j];
  double *dparm = dis->dparm[j];


  // Record the indexing parameters.  The first three are more widely used.
  iparm[I_DTYPE]  = DIS_POLYNOMIAL;
  iparm[I_NIPARM] = niparm;
  iparm[I_NDPARM] = ndparm;

  iparm[I_NIDX]   = I_NPOLY;
  iparm[I_LENDP]  = lendp;
  iparm[I_K]      = K;
  iparm[I_M]      = M;
  iparm[I_NKPARM] = nKparm;
  iparm[I_NTPARM] = nTparm;
  iparm[I_NVAR]   = nVar;
  iparm[I_MNVAR]  = M*nVar;
  iparm[I_DPOLY]  = K*nKparm;
  iparm[I_DAUX]   = ndparm;
  iparm[I_DVPOW]  = ndparm + K;
  iparm[I_MAXPOW] = iparm[I_NIDX];
  iparm[I_DPOFF]  = iparm[I_MAXPOW] + nVar;
  iparm[I_FLAGS]  = iparm[I_DPOFF]  + nVar;
  iparm[I_IPOW]   = iparm[I_FLAGS]  + M*nVar;

  // Set default values of POWER for the auxiliary variables.
  double *dptr = dparm + (1 + Nhat);
  for (int k = 0; k < K; k++) {
    for (int jhat = 0; jhat <= Nhat; jhat++) {
      dptr[jhat] = 1.0;
    }
    dptr += nKparm;
  }

  // Set default values of COEFF for the independent variables.
  dptr = dparm + iparm[I_DPOLY];
  for (int m = 0; m < M; m++) {
    *dptr = 1.0;
    dptr += nTparm;
  }

  // Extract parameter values from DPja or DQia.
  int i, k, m;
  k = m = 0;
  keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    // N.B. keyp->j is 1-relative, but j is 0-relative.
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "AUX.", 4) == 0) {
      // N.B. k here is 1-relative.
      fp += 4;
      sscanf(fp, "%d", &k);
      if (k < 1 || K < k) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
      }

      if ((fp = strchr(fp, '.')) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      int offset;
      if (strncmp(fp, "COEFF.", 6) == 0) {
        offset = 0;

      } else if (strncmp(fp, "POWER.", 6) == 0) {
        offset = 1 + Nhat;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 6;
      int jhat;
      sscanf(fp, "%d", &jhat);
      if (jhat < 0 || naxis < jhat) {
        // N.B. jhat == 0 is ok.
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid axis number (%d) for %s: %s", jhat, id, keyp->field);
      }

      i = (k-1)*nKparm + offset + jhat;
      dparm[i] = dpkeyd(keyp);

    } else if (strncmp(fp, "TERM.", 5) == 0) {
      // N.B. m here is 1-relative.
      fp += 5;
      sscanf(fp, "%d", &m);
      if (m < 1 || M < m) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad term (%d) for %s: %s", m, id, keyp->field);
      }

      if ((fp = strchr(fp, '.')) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      if (strcmp(fp, "COEFF") == 0) {
        i = iparm[I_DPOLY] + (m-1)*nTparm;
        dparm[i] = dpkeyd(keyp);

      } else if (strncmp(fp, "VAR.", 4) == 0) {
        // N.B. jhat here is 1-relative.
        fp += 4;
        int jhat;
        sscanf(fp, "%d", &jhat);
        if (jhat < 1 || naxis < jhat) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid axis number (%d) for %s: %s", jhat, id, keyp->field);
        }

        i = iparm[I_DPOLY] + (m-1)*nTparm + 1 + (jhat-1);
        double power = dpkeyd(keyp);
        dparm[i] = power;

      } else if (strncmp(fp, "AUX.", 4) == 0) {
        // N.B. k here is 1-relative.
        fp += 4;
        sscanf(fp, "%d", &k);
        if (k < 1 || K < k) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
            "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
        }

        i = iparm[I_DPOLY] + (m-1)*nTparm + 1 + Nhat + (k-1);
        double power = dpkeyd(keyp);
        dparm[i] = power;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

    } else if (strcmp(fp, "DOCORR") != 0 &&
               strcmp(fp, "NAXES")  != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0 &&
               strcmp(fp, "NAUX")   != 0 &&
               strcmp(fp, "NTERMS") != 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }


  // Optimization: when the power is integral, it is faster to multiply
  // ------------  repeatedly than call pow().  iparm[] is constructed as
  //               follows:
  //  I_NPOLY indexing parameters, as above,
  //     nVar elements record the largest integral power for each variable,
  //     nVar elements record offsets into dparm for each variable,
  //   M*nVar flags to signal whether the power is integral,
  //   M*nVar integral powers.
  for (int ivar = 0; ivar < nVar; ivar++) {
    // Want at least the first degree power for all variables.
    i = iparm[I_MAXPOW] + ivar;
    iparm[i] = 1;
  }

  for (int ivar = 0; ivar < nVar; ivar++) {
    for (m = 0; m < M; m++) {
      i = iparm[I_DPOLY] + m*nTparm + 1 + ivar;
      double power = dparm[i];

      // Is it integral?  (Positive, negative, or zero.)
      int ipow = (int)power;
      if (power == (double)ipow) {
        // Signal that the power is integral.
        i = iparm[I_FLAGS] + m*nVar + ivar;
        if (ipow == 0) {
          iparm[i] = 3;
        } else {
          iparm[i] = 1;
        }

        // The integral power itself.
        i = iparm[I_IPOW] + m*nVar + ivar;
        iparm[i] = ipow;
      }

      // Record the largest integral power for each variable.
      i = iparm[I_MAXPOW] + ivar;
      if (iparm[i] < abs(ipow)) {
        iparm[i] = abs(ipow);
      }
    }
  }

  // How many of all powers of each variable will there be?
  int npow = 0;
  for (int ivar = 0; ivar < nVar; ivar++) {
    // Offset into dparm.
    i = iparm[I_DPOFF] + ivar;
    iparm[i] = lendp + npow;

    i = iparm[I_MAXPOW] + ivar;
    npow += iparm[i];
  }

  // Expand dparm to store the extra powers.
  if (npow) {
    lendp += npow;
    iparm[I_LENDP] = lendp;
    if ((dis->dparm[j] = realloc(dparm, lendp*sizeof(double))) == 0x0) {
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
  }

  // No specialist de-distortions.
  dis->disp2x[j] = dispoly;
  dis->disx2p[j] = 0x0;

  // Translate Polynomial to TPD if possible, it's much faster.
  // However don't do it if the name was given as "Polynomial*".
  if (strcmp(dis->dtype[j], "Polynomial") == 0) {
    pol2tpd(j, dis);
  }

  return 0;
}

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

static int tpdset(int j, struct disprm *dis)

{
  static const char *function = "tpdset";

  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  char id[32];
  snprintf(id, 32, "TPD on axis %d", j+1);


  // TPD distortion.
  if (dis->Nhat[j] < 1 || 2 < dis->Nhat[j]) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 1 or 2 entries, not %d", id,
      dis->Nhat[j]);
  }

  // Find the number of parameters.
  int ncoeff[2] = {0, 0};
  int doaux     = 0;
  int doradial  = 0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      int idis;
      if (strncmp(fp, "FWD.", 4) == 0) {
        idis = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        // TPD may provide a polynomial approximation for the inverse.
        idis = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      int k;
      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 59) {
        if (ncoeff[idis] < k+1) ncoeff[idis] = k+1;

        // Any radial terms?
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }

    } else if (strncmp(fp, "AUX.", 4) == 0) {
      // Flag usage of auxiliary variables.
      doaux = 1;

    } else if (strcmp(fp, "DOCORR") != 0 &&
               strcmp(fp, "NAXES")  != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  int (*(distpd[2]))(DISP2X_ARGS) = {0x0, 0x0};
  for (int idis = 0; idis < 2; idis++) {
    if (ncoeff[idis] <= 4) {
      if (idis) {
        // No inverse polynomial.
        break;
      }

      // First degree.
      ncoeff[idis] = 4;
      distpd[idis] = tpd1;
    } else if (ncoeff[idis] <= 7) {
      // Second degree.
      ncoeff[idis] = 7;
      distpd[idis] = tpd2;
    } else if (ncoeff[idis] <= 12) {
      // Third degree.
      ncoeff[idis] = 12;
      distpd[idis] = tpd3;
    } else if (ncoeff[idis] <= 17) {
      // Fourth degree.
      ncoeff[idis] = 17;
      distpd[idis] = tpd4;
    } else if (ncoeff[idis] <= 24) {
      // Fifth degree.
      ncoeff[idis] = 24;
      distpd[idis] = tpd5;
    } else if (ncoeff[idis] <= 31) {
      // Sixth degree.
      ncoeff[idis] = 31;
      distpd[idis] = tpd6;
    } else if (ncoeff[idis] <= 40) {
      // Seventh degree.
      ncoeff[idis] = 40;
      distpd[idis] = tpd7;
    } else if (ncoeff[idis] <= 49) {
      // Eighth degree.
      ncoeff[idis] = 49;
      distpd[idis] = tpd8;
    } else if (ncoeff[idis] <= 60) {
      // Ninth degree.
      ncoeff[idis] = 60;
      distpd[idis] = tpd9;
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid number of parameters (%d) for %s", ncoeff[idis], id);
    }
  }

  // disx2p() only uses the inverse TPD, if present, to provide a better
  // zeroth approximation.
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


// These iparm indices are specific to TPD (matching definitions in wcshdr.c).
#define I_TPDNCO  3	// No. of TPD coefficients, forward...
#define I_TPDINV  4	// ...and inverse.
#define I_TPDAUX  5	// True if auxiliary variables are used.
#define I_TPDRAD  6	// True if the radial variable is used.
#define I_NTPD    7

  // Record indexing parameters.
  int niparm = I_NTPD;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  int ndparm = (doaux?6:0) + ncoeff[0] + ncoeff[1];

  // The first three are more widely used.
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;

  // Number of TPD coefficients.
  dis->iparm[j][I_TPDNCO] = ncoeff[0];
  dis->iparm[j][I_TPDINV] = ncoeff[1];

  // Flag for presence of auxiliary variables.
  dis->iparm[j][I_TPDAUX] = doaux;

  // Flag for presence of radial terms.
  dis->iparm[j][I_TPDRAD] = doradial;


  // Allocate memory for the polynomial coefficients and fill it.
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  // Set default auxiliary coefficients.
  if (doaux) {
    dis->dparm[j][1] = 1.0;
    dis->dparm[j][5] = 1.0;
  }

  keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "AUX.", 4) == 0) {
      // Auxiliary variables.
      fp += 4;
      int k;
      sscanf(fp, "%d", &k);
      if (k < 1 || 2 < k) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
      }

      if ((fp = strchr(fp, '.')) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      if (strncmp(fp, "COEFF.", 6) != 0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 6;
      int m;
      sscanf(fp, "%d", &m);
      if (m < 0 || 2 < m) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid coefficient number (%d) for %s: %s", m, id, keyp->field);
      }

      int idis = 3*(k-1) + m;
      dis->dparm[j][idis] = dpkeyd(keyp);

    } else if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      int idis = (doaux?6:0);
      if (strncmp(fp, "REV.", 4) == 0) {
        idis += ncoeff[0];
      }

      int k;
      sscanf(fp+4, "%d", &k);
      dis->dparm[j][idis+k] = dpkeyd(keyp);
    }
  }

  return 0;
}

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

static int pol2tpd(int j, struct disprm *dis)

{
  static const char *function = "pol2tpd";

  static const int map[][10] = {{ 0,  2,  6, 10, 16, 22, 30, 38, 48, 58},
                                { 1,  5,  9, 15, 21, 29, 37, 47, 57, -1},
                                { 4,  8, 14, 20, 28, 36, 46, 56, -1, -1},
                                { 7, 13, 19, 27, 35, 45, 55, -1, -1, -1},
                                {12, 18, 26, 34, 44, 54, -1, -1, -1, -1},
                                {17, 25, 33, 43, 53, -1, -1, -1, -1, -1},
                                {24, 32, 42, 52, -1, -1, -1, -1, -1, -1},
                                {31, 41, 51, -1, -1, -1, -1, -1, -1, -1},
                                {40, 50, -1, -1, -1, -1, -1, -1, -1, -1},
                                {49, -1, -1, -1, -1, -1, -1, -1, -1, -1}};

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  int    *iparm = dis->iparm[j];
  double *dparm = dis->dparm[j];


  // Check the number of independent variables, no more than two.
  int Nhat = dis->Nhat[j];
  if (2 < Nhat) return -1;

  // Check auxiliaries: only one is allowed...
  int K = iparm[I_K];
  if (1 < K) return -1;
  if (K) {
    // ...and it must be radial.
    if (dparm[0] != 0.0) return -1;
    if (dparm[1] != 1.0) return -1;
    if (dparm[2] != 1.0) return -1;
    if (dparm[3] != 0.5) return -1;
    if (dparm[4] != 2.0) return -1;
    if (dparm[5] != 2.0) return -1;
  }

  // Check powers...
  int *iflgp = iparm + iparm[I_FLAGS];
  int *ipowp = iparm + iparm[I_IPOW];
  int degree = 0;
  for (int m = 0; m < iparm[I_M]; m++) {
    int deg = 0;
    for (int jhat = 0; jhat < Nhat; jhat++) {
      // ...they must be positive integral.
      if (*iflgp == 0)  return -1;
      if (*ipowp < 0)   return -1;
      deg += *ipowp;
      iflgp++;
      ipowp++;
    }

    // The polynomial degree can't be greater than 9.
    if (9 < deg) return -1;

    if (K) {
      // Likewise for the radial variable.
      if (*iflgp == 0)  return -1;
      if (*ipowp) {
        if (*ipowp < 0) return -1;
        if (9 < *ipowp) return -1;

        // Can't mix the radial and other terms.
        if (deg)        return -1;

        // Can't have even powers of the radial variable.
        deg = *ipowp;
        if (9 < deg)    return -1;
        if (!(deg%2))   return -1;
      }
      iflgp++;
      ipowp++;
    }

    if (degree < deg) degree = deg;
  }


  // OK, it ticks all the boxes.  Now translate it.
  int ndparm = 0;
  if (degree == 1) {
    ndparm = 4;
    dis->disp2x[j] = tpd1;
  } else if (degree == 2) {
    ndparm = 7;
    dis->disp2x[j] = tpd2;
  } else if (degree == 3) {
    ndparm = 12;
    dis->disp2x[j] = tpd3;
  } else if (degree == 4) {
    ndparm = 17;
    dis->disp2x[j] = tpd4;
  } else if (degree == 5) {
    ndparm = 24;
    dis->disp2x[j] = tpd5;
  } else if (degree == 6) {
    ndparm = 31;
    dis->disp2x[j] = tpd6;
  } else if (degree == 7) {
    ndparm = 40;
    dis->disp2x[j] = tpd7;
  } else if (degree == 8) {
    ndparm = 49;
    dis->disp2x[j] = tpd8;
  } else if (degree == 9) {
    ndparm = 60;
    dis->disp2x[j] = tpd9;
  } else {
    // Can't happen; this is just to appease clang-tidy.
    return -1;
  }

  // No specialist de-distortions.
  dis->disx2p[j] = 0x0;

  // Record indexing parameters.
  int niparm = I_NTPD;
  int *tpd_iparm;
  if ((tpd_iparm = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  // The first three are more widely used.
  tpd_iparm[I_DTYPE]  = DIS_TPD;
  tpd_iparm[I_NIPARM] = niparm;
  tpd_iparm[I_NDPARM] = ndparm;

  // Number of TPD coefficients.
  tpd_iparm[I_TPDNCO] = ndparm;
  tpd_iparm[I_TPDINV] = 0;

  // No auxiliary variables yet.
  tpd_iparm[I_TPDAUX] = 0;

  // Flag for presence of radial terms.
  tpd_iparm[I_TPDRAD] = K;


  // Allocate memory for the polynomial coefficients and fill it.
  double *tpd_dparm;
  if ((tpd_dparm = calloc(ndparm, sizeof(double))) == 0x0) {
    free(tpd_iparm);
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  ipowp = iparm + iparm[I_IPOW];
  double *dpolp = dparm + iparm[I_DPOLY];
  for (int m = 0; m < iparm[I_M]; m++) {
    if (K && ipowp[Nhat]) {
      // The radial variable.
      switch (ipowp[Nhat]) {
      case 1:
        tpd_dparm[3]  = *dpolp;
        break;
      case 3:
        tpd_dparm[11] = *dpolp;
        break;
      case 5:
        tpd_dparm[23] = *dpolp;
        break;
      case 7:
        tpd_dparm[39] = *dpolp;
        break;
      case 9:
        tpd_dparm[59] = *dpolp;
        break;
      default:
        // Nothing.
        break;
      }

    } else {
      // The independent variables.
      int p[] = {0, 0};
      for (int jhat = 0; jhat < Nhat; jhat++) {
        p[jhat] = ipowp[jhat];
      }

      int n = map[p[0]][p[1]];
      tpd_dparm[n] = *dpolp;
    }


    ipowp += iparm[I_NVAR];
    dpolp += iparm[I_NVAR] + 1;
  }


  // Switch from Polynomial to TPD.
  free(iparm);
  free(dparm);
  dis->iparm[j] = tpd_iparm;
  dis->dparm[j] = tpd_dparm;

  return 0;
}

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

static int tpvset(int j, struct disprm *dis)

{
  static const char *function = "tpvset";

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  // TPV "projection".
  char id[32];
  snprintf(id, 32, "TPV on axis %d", j+1);

  // TPV is a sequent distortion, applied to intermediate world coordinates
  // (normally used with CDi_ja).  It computes corrected coordinates directly.
  dis->docorr[j] = 0;

  if (dis->Nhat[j] != 2) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
  }

  // Find the number of parameters.
  int ndparm   = 0;
  int doradial = 0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "TPV.", 4) == 0) {
      int k;
      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 39) {
        if (ndparm < k+1) ndparm = k+1;

        // Any radial terms?
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  // TPD is going to do the dirty work.
  if (ndparm <= 4) {
    // First degree.
    ndparm = 4;
    dis->disp2x[j] = tpd1;
  } else if (ndparm <= 7) {
    // Second degree.
    ndparm = 7;
    dis->disp2x[j] = tpd2;
  } else if (ndparm <= 12) {
    // Third degree.
    ndparm = 12;
    dis->disp2x[j] = tpd3;
  } else if (ndparm <= 17) {
    // Fourth degree.
    ndparm = 17;
    dis->disp2x[j] = tpd4;
  } else if (ndparm <= 24) {
    // Fifth degree.
    ndparm = 24;
    dis->disp2x[j] = tpd5;
  } else if (ndparm <= 31) {
    // Sixth degree.
    ndparm = 31;
    dis->disp2x[j] = tpd6;
  } else if (ndparm <= 40) {
    // Seventh degree.
    ndparm = 40;
    dis->disp2x[j] = tpd7;
  } else {
    // Could go to ninth degree, but that wouldn't be legit.
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Invalid number of parameters (%d) for %s", ndparm, id);
  }

  // No specialist de-distortions.
  dis->disx2p[j] = 0x0;

  // Record indexing parameters.
  int niparm = I_NTPD;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  // The first three are more widely used.
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;

  // Number of TPD coefficients.
  dis->iparm[j][I_TPDNCO] = ndparm;
  dis->iparm[j][I_TPDINV] = 0;

  // TPV never needs auxiliary variables.
  dis->iparm[j][I_TPDAUX] = 0;

  // Flag for presence of radial terms.
  dis->iparm[j][I_TPDRAD] = doradial;


  // Allocate memory for the polynomial coefficients and fill it.
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    // One-to-one correspondence between TPV and TPD coefficients.
    if (strncmp(fp, "TPV.", 4) == 0) {
      int k;
      sscanf(fp+4, "%d", &k);
      dis->dparm[j][k] = dpkeyd(keyp);
    }
  }

  return 0;
}

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

static int sipset(int j, struct disprm *dis)

{
  static const char *function = "sipset";

  static const int map[][10] = {{ 0,  2,  6, 10, 16, 22, 30, 38, 48, 58},
                                { 1,  5,  9, 15, 21, 29, 37, 47, 57, -1},
                                { 4,  8, 14, 20, 28, 36, 46, 56, -1, -1},
                                { 7, 13, 19, 27, 35, 45, 55, -1, -1, -1},
                                {12, 18, 26, 34, 44, 54, -1, -1, -1, -1},
                                {17, 25, 33, 43, 53, -1, -1, -1, -1, -1},
                                {24, 32, 42, 52, -1, -1, -1, -1, -1, -1},
                                {31, 41, 51, -1, -1, -1, -1, -1, -1, -1},
                                {40, 50, -1, -1, -1, -1, -1, -1, -1, -1},
                                {49, -1, -1, -1, -1, -1, -1, -1, -1, -1}};

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  // Simple Imaging Polynomial.
  char id[32];
  snprintf(id, 32, "SIP on axis %d", j+1);


  // SIP is a prior distortion that computes an additive correction.
  dis->docorr[j] = 1;

  if (dis->Nhat[j] != 2) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
  }

  // Find the polynomial degree, at least 1 for the forward function.
  int degree[2] = {1, -1};
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "SIP.", 4) == 0) {
      fp += 4;
      int idis;
      if (strncmp(fp, "FWD.", 4) == 0) {
        idis = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        // SIP uses a polynomial approximation for the inverse.
        idis = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 4;
      int p, q;
      sscanf(fp, "%d_%d", &p, &q);
      int deg = p + q;
      if (p < 0 || 9 < p || q < 0 || 9 < q || 9 < deg) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid powers (%d, %d) for %s: %s", p, q, id, keyp->field);
      }

      if (degree[idis] < deg) degree[idis] = deg;

    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  if (degree[1] == 0 ) degree[1] = 1;

  // TPD is going to do the dirty work.
  int (*(distpd[2]))(DISP2X_ARGS) = {0x0, 0x0}, ncoeff[2];
  for (int idis = 0; idis < 2; idis++) {
    ncoeff[idis] = 0;
    if (degree[idis] == 1) {
      ncoeff[idis] = 4;
      distpd[idis] = tpd1;
    } else if (degree[idis] == 2) {
      ncoeff[idis] = 7;
      distpd[idis] = tpd2;
    } else if (degree[idis] == 3) {
      ncoeff[idis] = 12;
      distpd[idis] = tpd3;
    } else if (degree[idis] == 4) {
      ncoeff[idis] = 17;
      distpd[idis] = tpd4;
    } else if (degree[idis] == 5) {
      ncoeff[idis] = 24;
      distpd[idis] = tpd5;
    } else if (degree[idis] == 6) {
      ncoeff[idis] = 31;
      distpd[idis] = tpd6;
    } else if (degree[idis] == 7) {
      ncoeff[idis] = 40;
      distpd[idis] = tpd7;
    } else if (degree[idis] == 8) {
      ncoeff[idis] = 49;
      distpd[idis] = tpd8;
    } else if (degree[idis] == 9) {
      ncoeff[idis] = 60;
      distpd[idis] = tpd9;
    } else {
      // Can't happen; this is just to appease clang-tidy.
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Degree must not exceed 9, got %d", degree[idis]);
    }
  }

  // SIP uses a polynomial approximation to the inverse.  It's not very
  // accurate but may provide disx2p() with a better zeroth approximation.
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


  // Record indexing parameters.
  int niparm = I_NTPD;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  int ndparm = ncoeff[0] + ncoeff[1];

  // The first three are more widely used.
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;

  // Number of TPD coefficients.
  dis->iparm[j][I_TPDNCO] = ncoeff[0];
  dis->iparm[j][I_TPDINV] = ncoeff[1];

  // SIP never needs auxiliary variables.
  dis->iparm[j][I_TPDAUX] = 0;

  // SIP never needs the radial terms.
  dis->iparm[j][I_TPDRAD] = 0;


  // Allocate memory for the polynomial coefficients and fill it.
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "SIP.", 4) == 0) {
      fp += 4;
      int idis;
      if (strncmp(fp, "FWD.", 4) == 0) {
        idis = 0;
      } else {
        idis = ncoeff[0];
      }

      int p, q;
      sscanf(fp+4, "%d_%d", &p, &q);

      // Map to TPD coefficient number.
      idis += map[p][q];

      dis->dparm[j][idis] = dpkeyd(keyp);
    }
  }


  return 0;
}

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

static int dssset(int j, struct disprm *dis)

{
  static const char *function = "dssset";

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  // Digitized Sky Survey.
  char id[32];
  snprintf(id, 32, "DSS on axis %d", j+1);


  // DSS is translated into a sequent distortion, applied to intermediate
  // pixel coordinates.  It computes corrected coordinates directly.
  dis->docorr[j] = 0;

  if (dis->Nhat[j] != 2) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
  }

  // Safe to assume the polynomial degree is 5 (or less).
  int ncoeff = 24;
  dis->disp2x[j] = tpd5;

  // No specialist de-distortions.
  dis->disx2p[j] = 0x0;


  // Record indexing parameters.
  int niparm = I_NTPD;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  int ndparm = 6 + ncoeff;

  // The first three are more widely used.
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;

  // Number of TPD coefficients.
  dis->iparm[j][I_TPDNCO] = ncoeff;
  dis->iparm[j][I_TPDINV] = 0;

  // DSS always needs auxiliary variables.
  dis->iparm[j][I_TPDAUX] = 1;

  // DSS never needs the radial terms.
  dis->iparm[j][I_TPDRAD] = 0;


  // Allocate memory for the polynomial coefficients and fill it.
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  // This translation follows WCS Paper IV, Sect. 5.2 using the same
  // variable names.  Find A1, A2, A3, B1, B2, and B3.
  double A1, A2, A3, B1, B2, B3;
  A1 = A2 = A3 = 0.0;
  B1 = B2 = B3 = 0.0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    char *fp = strchr(keyp->field, '.') + 1;
    if (strncmp(fp, "DSS.AMD.", 8) == 0) {
      fp += 8;
      int m;
      sscanf(fp, "%d", &m);

      if (m == 1) {
        if (keyp->j == 1) {
          A1 = dpkeyd(keyp);
        } else {
          B1 = dpkeyd(keyp);
        }
      } else if (m == 2) {
        if (keyp->j == 1) {
          A2 = dpkeyd(keyp);
        } else {
          B2 = dpkeyd(keyp);
        }
      } else if (m == 3) {
        if (keyp->j == 1) {
          A3 = dpkeyd(keyp);
        } else {
          B3 = dpkeyd(keyp);
        }
      }
    }
  }

  double X0 = (A2*B3 - A3*B1) / (A1*B1 - A2*B2);
  double Y0 = (A3*B2 - A1*B3) / (A1*B1 - A2*B2);

  double S = sqrt(fabs(A1*B1 - A2*B2));
  if (S == 0.0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Coefficient scale for %s is zero.", id);
  }

  // Coefficients for the auxiliary variables.
  double *dparm = dis->dparm[j];
  if (j == 0) {
    dparm[0] =  X0;
    dparm[1] = -B1/S;
    dparm[2] = -A2/S;
    dparm[3] =  Y0;
    dparm[4] =  B2/S;
    dparm[5] =  A1/S;

    // Change the sign of S for scaling the A coefficients.
    S *= -1.0;

  } else {
    dparm[0] =  Y0;
    dparm[1] =  B2/S;
    dparm[2] =  A1/S;
    dparm[3] =  X0;
    dparm[4] = -B1/S;
    dparm[5] = -A2/S;
  }

  // Translate DSS coefficients to TPD.
  dparm += 6;
  int degree = 3;
  keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "DSS.AMD.", 8) == 0) {
      // Skip zero coefficients.
      double coeff = dpkeyd(keyp);
      if (coeff == 0.0) continue;

      fp += 8;
      int m;
      sscanf(fp, "%d", &m);

      // Apply the coefficient scale factor.
      coeff /= S;

      if (m == 1) {
        dparm[1]  = coeff;
      } else if (m == 2) {
        dparm[2]  = coeff;
      } else if (m == 3) {
        dparm[0]  = coeff;
      } else if (m == 4) {
        dparm[4] += coeff;
      } else if (m == 5) {
        dparm[5]  = coeff;
      } else if (m == 6) {
        dparm[6] += coeff;
      } else if (m == 7) {
        dparm[4] += coeff;
        dparm[6] += coeff;
      } else if (m == 8) {
        dparm[7] += coeff;
      } else if (m == 9) {
        dparm[8]  = coeff;
      } else if (m == 10) {
        dparm[9] += coeff;
      } else if (m == 11) {
        dparm[10] = coeff;
      } else if (m == 12) {
        dparm[7] += coeff;
        dparm[9] += coeff;
      } else if (m == 13) {
        dparm[17] = coeff;
        dparm[19] = coeff * 2.0;
        dparm[21] = coeff;
        degree = 5;
      } else if (coeff != 0.0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid parameter for %s: %s", m, id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  // The DSS polynomial doesn't have 4th degree terms, and the 5th degree
  // coefficient is often zero.
  if (degree == 3) {
    dis->iparm[j][I_TPDNCO] = 12;
    dis->disp2x[j] = tpd3;
  }

  return 0;
}

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

#define CHEBYSHEV 1
#define LEGENDRE  2
#define MONOMIAL  3

static int watset(int j, struct disprm *dis)

{
  static const char *function = "watset";

  static const int map[][10] = {{ 0,  2,  6, 10, 16, 22, 30, 38, 48, 58},
                                { 1,  5,  9, 15, 21, 29, 37, 47, 57, -1},
                                { 4,  8, 14, 20, 28, 36, 46, 56, -1, -1},
                                { 7, 13, 19, 27, 35, 45, 55, -1, -1, -1},
                                {12, 18, 26, 34, 44, 54, -1, -1, -1, -1},
                                {17, 25, 33, 43, 53, -1, -1, -1, -1, -1},
                                {24, 32, 42, 52, -1, -1, -1, -1, -1, -1},
                                {31, 41, 51, -1, -1, -1, -1, -1, -1, -1},
                                {40, 50, -1, -1, -1, -1, -1, -1, -1, -1},
                                {49, -1, -1, -1, -1, -1, -1, -1, -1, -1}};

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;
  struct wcserr **err = &(dis->err);

  // WAT (TNX or ZPX) Polynomial.
  char id[32];
  snprintf(id, 32, "WAT (%s) on axis %d", dis->dtype[0]+4, j+1);


  // WAT is a sequent distortion, applied to intermediate world coordinates
  // (normally used with CDi_ja).  It computes an additive correction.
  dis->docorr[j] = 1;

  if (dis->Nhat[j] != 2) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
  }

  // Find the polynomial degree (at least 1), kind, and domain.
  int degree = 1;
  int kind = 0;
  double xmin = 0.0;
  double xmax = 0.0;
  double ymin = 0.0;
  double ymax = 0.0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "WAT.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "CHBY.", 5) == 0 ||
          strncmp(fp, "LEGR.", 5) == 0 ||
          strncmp(fp, "MONO.", 5) == 0) {

        fp += 5;
        int m, n;
        sscanf(fp, "%d_%d", &m, &n);
        int deg = m + n;
        if (m < 0 || 9 < m || n < 0 || 9 < n || 9 < deg) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid powers (%d, %d) for %s: %s", m, n, id, keyp->field);
        }

        if (degree < deg) degree = deg;

      } else if (strcmp(fp, "POLY") == 0) {
        kind = dpkeyi(keyp);

      } else if (strcmp(fp, "XMIN") == 0) {
        xmin = dpkeyd(keyp);

      } else if (strcmp(fp, "XMAX") == 0) {
        xmax = dpkeyd(keyp);

      } else if (strcmp(fp, "YMIN") == 0) {
        ymin = dpkeyd(keyp);

      } else if (strcmp(fp, "YMAX") == 0) {
        ymax = dpkeyd(keyp);
      }

    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  int doaux = (kind == 1 || kind == 2);

  // TPD is going to do the dirty work.
  int ncoeff = 0;
  if (degree == 1) {
    // First degree.
    ncoeff = 4;
    dis->disp2x[j] = tpd1;
  } else if (degree == 2) {
    // Second degree.
    ncoeff = 7;
    dis->disp2x[j] = tpd2;
  } else if (degree == 3) {
    // Third degree.
    ncoeff = 12;
    dis->disp2x[j] = tpd3;
  } else if (degree == 4) {
    // Fourth degree.
    ncoeff = 17;
    dis->disp2x[j] = tpd4;
  } else if (degree == 5) {
    // Fifth degree.
    ncoeff = 24;
    dis->disp2x[j] = tpd5;
  } else if (degree == 6) {
    // Sixth degree.
    ncoeff = 31;
    dis->disp2x[j] = tpd6;
  } else if (degree == 7) {
    // Seventh degree.
    ncoeff = 40;
    dis->disp2x[j] = tpd7;
  } else if (degree == 8) {
    // Eighth degree.
    ncoeff = 49;
    dis->disp2x[j] = tpd8;
  } else if (degree == 9) {
    // Ninth degree.
    ncoeff = 60;
    dis->disp2x[j] = tpd9;
  }

  // No specialist de-distortions.
  dis->disx2p[j] = 0x0;


  // Record indexing parameters.
  int niparm = I_NTPD;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  int *iparm = dis->iparm[j];

  int ndparm = 6 + ncoeff;

  // The first three are more widely used.
  iparm[I_DTYPE]  = DIS_TPD;
  iparm[I_NIPARM] = niparm;
  iparm[I_NDPARM] = ndparm;

  // Number of TPD coefficients.
  iparm[I_TPDNCO] = ncoeff;
  iparm[I_TPDINV] = 0;

  // The Chebyshev and Legendre polynomials use auxiliary variables.
  iparm[I_TPDAUX] = doaux;

  // WAT never needs the radial terms.
  iparm[I_TPDRAD] = 0;


  // Allocate memory for the polynomial coefficients and fill it.
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  double *dparm = dis->dparm[j];


  // Coefficients for the auxiliary variables.
  if (doaux) {
    double x0 = (xmax + xmin)/2.0;
    double dx = (xmax - xmin)/2.0;
    if (dx == 0.0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "X-span for %s is zero", id);
    }

    dparm[0] = -x0/dx;
    dparm[1] = 1.0/dx;
    dparm[2] = 0.0;

    double y0 = (ymax + ymin)/2.0;
    double dy = (ymax - ymin)/2.0;
    if (dy == 0.0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Y-span for %s is zero", id);
    }

    dparm[3] = -y0/dy;
    dparm[4] = 0.0;
    dparm[5] = 1.0/dy;

    dparm += 6;
  }


  // Unpack the polynomial coefficients.
  keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    char *fp = strchr(keyp->field, '.') + 1;

    if ((kind == CHEBYSHEV && strncmp(fp, "WAT.CHBY.", 9) == 0) ||
        (kind == LEGENDRE  && strncmp(fp, "WAT.LEGR.", 9) == 0) ||
        (kind == MONOMIAL  && strncmp(fp, "WAT.MONO.", 9) == 0)) {
      fp += 9;

      int m, n;
      sscanf(fp, "%d_%d", &m, &n);

      if (kind == MONOMIAL) {
        // Monomial coefficient, maps simply to TPD coefficient number.
        int idis = map[m][n];
        dparm[idis] = dpkeyd(keyp);

      } else {
        // Coefficient of the product of two Chebyshev or two Legendre
        // polynomials.  Find the corresponding monomial coefficients.
        double coeff = dpkeyd(keyp);

        int status;
        double coeffm[10], coeffn[10];
        if ((status = cheleg(kind, m, n, coeffm, coeffn))) {
          return wcserr_set(DIS_ERRMSG(status));
        }

        for (int im = 0; im <= m; im++) {
          if (coeffm[im] == 0.0) continue;

          for (int in = 0; in <= n; in++) {
            if (coeffn[in] == 0.0) continue;

            int idis = map[im][in];
            dparm[idis] += coeff*coeffm[im]*coeffn[in];
          }
        }
      }
    }
  }

  return 0;
}

//----------------------------------------------------------------------------
// Compute the coefficients of Chebyshev or Legendre polynomials of degree
// m and n.

static int cheleg(int kind, int m, int n, double coeffm[], double coeffn[])

{
  int N = (n < m) ? m : n;
  if (N < 0) {
    return DISERR_BAD_PARAM;
  }

  // Allocate work arrays.
  double *coeff[3], *dp;
  if ((dp = calloc(3*(size_t)(N+1), sizeof(double))) == 0x0) {
    return DISERR_MEMORY;
  }
  coeff[0] = dp;
  coeff[1] = coeff[0] + (N+1);
  coeff[2] = coeff[1] + (N+1);

  for (int j = 0; j <= N; j++) {
    int j0 = j%3;

    if (j == 0) {
      coeff[0][0] = 1.0;

    } else if (j == 1) {
      coeff[1][1] = 1.0;

    } else {
      // Cyclic buffer indices.
      int j1 = (j-1)%3;
      int j2 = (j-2)%3;

      memset(coeff[j0], 0, (N+1)*sizeof(double));

      double d = (double)j;
      for (int k = 0; k < N; k++) {
        if (kind == CHEBYSHEV) {
          coeff[j0][k+1] = 2.0 * coeff[j1][k];
          coeff[j0][k]  -=       coeff[j2][k];
        } else if (kind == LEGENDRE) {
          coeff[j0][k+1] = ((2.0*d - 1.0) * coeff[j1][k]) / d;
          coeff[j0][k]  -=     ((d - 1.0) * coeff[j2][k]) / d;
        }
      }
    }

    if (j == m) memcpy(coeffm, coeff[j0], (m+1)*sizeof(double));
    if (j == n) memcpy(coeffn, coeff[j0], (n+1)*sizeof(double));
  }

  free(dp);

  return 0;
}

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

static int dispoly(
  int dummy,
  const int iparm[],
  const double dparm[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

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

  // Check for zeroes.
  for (int jhat = 0; jhat < Nhat; jhat++) {
    if (rawcrd[jhat] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }

  // Working memory for auxiliaries &c. was allocated at the end of p[].
  double *aux = (double *)(dparm + iparm[I_DAUX]);

  // Compute the auxiliary variables.
  for (int k = 0; k < iparm[I_K]; k++) {
    const double *cptr = dparm + (ptrdiff_t)(k*iparm[I_NKPARM]);
    const double *pptr = cptr  + (ptrdiff_t)(1+Nhat);

    aux[k] = *(cptr++);
    double auxp0 = *(pptr++);

    for (int jhat = 0; jhat < Nhat; jhat++) {
      aux[k] += *(cptr++)*pow(rawcrd[jhat], *(pptr++));
    }

    aux[k] = pow(aux[k], auxp0);

    // Check for zeroes.
    if (aux[k] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }


  // Compute all required integral powers of the variables.
  const int *imaxpow = iparm + iparm[I_MAXPOW];
  double *dvarpow = (double *)(dparm + iparm[I_DVPOW]);

  const int *imaxp = imaxpow;
  double *dpowp = dvarpow;
  for (int jhat = 0; jhat < Nhat; jhat++, imaxp++) {
    double var = 1.0;
    for (int ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= rawcrd[jhat];
      *dpowp = var;
    }
  }

  for (int k = 0; k < iparm[I_K]; k++, imaxp++) {
    double var = 1.0;
    for (int ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= aux[k];
      *dpowp = var;
    }
  }

  // Loop for each term of the polynomial.
  *discrd = 0.0;
  const int    *iflgp = iparm + iparm[I_FLAGS];
  const int    *ipowp = iparm + iparm[I_IPOW];
  const double *dpolp = dparm + iparm[I_DPOLY];
  for (int m = 0; m < iparm[I_M]; m++) {
    double term = *(dpolp++);

    // Loop over all variables.
    imaxp = imaxpow;
    dpowp = dvarpow - 1;
    for (int ivar = 0; ivar < iparm[I_NVAR]; ivar++) {
      if (*iflgp & 2) {
        // Nothing (zero power).

      } else if (*iflgp) {
        // Integral power.
        if (*ipowp < 0) {
          // Negative.
          term /= dpowp[*ipowp];
        } else {
          // Positive.
          term *= dpowp[*ipowp];
        }

      } else {
        // Fractional power.
        term *= pow(dpowp[0], *dpolp);
      }

      iflgp++;
      ipowp++;
      dpolp++;

      dpowp += *imaxp;
      imaxp++;
    }

    *discrd += term;
  }

  return 0;
}

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

static int tpd1(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 4 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // First degree.
  *discrd = p[0] + u*p[1];

  if (Nhat == 1) return 0;

  *discrd += v*p[2];

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*p[3];
  }

  return 0;
}

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

static int tpd2(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 7 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Second degree.
  *discrd = p[0] + u*(p[1] + u*(p[4]));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]))
    + u*(p[5])*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*p[3];
  }

  return 0;
}

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

static int tpd3(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 12 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Third degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7])));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10])))
    + u*(p[5]  + v*(p[9])
    + u*(p[8]))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11]));
  }

  return 0;
}

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

static int tpd4(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 17 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Fourth degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12]))));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16]))))
    + u*(p[5]  + v*(p[9]  + v*(p[15]))
    + u*(p[8]  + v*(p[14])
    + u*(p[13])))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11]));
  }

  return 0;
}

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

static int tpd5(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 24 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Fifth degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17])))));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22])))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21])))
    + u*(p[8]  + v*(p[14] + v*(p[20]))
    + u*(p[13] + v*(p[19])
    + u*(p[18]))))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23])));
  }

  return 0;
}

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

static int tpd6(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 31 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Sixth degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24]))))));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30]))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29]))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28])))
    + u*(p[13] + v*(p[19] + v*(p[27]))
    + u*(p[18] + v*(p[26])
    + u*(p[25])))))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23])));
  }

  return 0;
}

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

static int tpd7(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 40 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Seventh degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24] + u*(p[31])))))));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38])))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37])))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36]))))
    + u*(p[13] + v*(p[19] + v*(p[27] + v*(p[35])))
    + u*(p[18] + v*(p[26] + v*(p[34]))
    + u*(p[25] + v*(p[33])
    + u*(p[32]))))))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23] + s*(p[39]))));
  }

  return 0;
}

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

static int tpd8(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 49 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Eighth degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24] + u*(p[31] + u*(p[40]))))))));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38] + v*(p[48]))))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37] + v*(p[47]))))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36] + v*(p[46])))))
    + u*(p[13] + v*(p[19] + v*(p[27] + v*(p[35] + v*(p[45]))))
    + u*(p[18] + v*(p[26] + v*(p[34] + v*(p[44])))
    + u*(p[25] + v*(p[33] + v*(p[43]))
    + u*(p[32] + v*(p[42])
    + u*(p[41])))))))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23] + s*(p[39]))));
  }

  return 0;
}

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

static int tpd9(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  if (i[I_TPDNCO+inverse] != 60 || 2 < Nhat) {
    return 1;
  }

  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];

  // Auxiliary variables?
  if (i[I_TPDAUX]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[I_TPDNCO];

  // Ninth degree.
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24] + u*(p[31] + u*(p[40] + u*(p[49])))))))));

  if (Nhat == 1) return 0;

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38] + v*(p[48] + v*(p[58])))))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37] + v*(p[47] + v*(p[57])))))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36] + v*(p[46] + v*(p[56]))))))
    + u*(p[13] + v*(p[19] + v*(p[27] + v*(p[35] + v*(p[45] + v*(p[55])))))
    + u*(p[18] + v*(p[26] + v*(p[34] + v*(p[44] + v*(p[54]))))
    + u*(p[25] + v*(p[33] + v*(p[43] + v*(p[53])))
    + u*(p[32] + v*(p[42] + v*(p[52]))
    + u*(p[41] + v*(p[51])
    + u*(p[50]))))))))*v;

  // Radial terms?
  if (i[I_TPDRAD]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23] + s*(p[39] + s*(p[59])))));
  }

  return 0;
}
@


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: dis.c,v 8.5.1.2 2026/03/29 13:36:16 mcalabre Exp mcalabre $
d27 1
d32 1
a36 3
// Maximum number of DPja or DQia keywords.
int NDPMAX = 256;

d104 1
a104 1
          sprintf(dp->field, "%s%d.%s", keyword, j, field);
d108 2
a109 2
          sprintf(dp->field, "%s.%s", keyword, field);
          sprintf(axno, "%d", j);
d114 1
a114 1
        sprintf(dp->field, "%s.%s", keyword, field);
d117 1
a117 1
      strcpy(dp->field, keyword);
d120 1
a120 1
    strcpy(dp->field, field);
d221 1
d223 1
a223 1
    return wcserr_set(WCSERR_SET(DISERR_MEMORY),
d227 5
d354 3
a356 1
  memcpy(disdst->dp, dissrc->dp, dissrc->ndpmax*sizeof(struct dpkey));
d392 3
a394 3
    if (dis->axmap)  free(dis->axmap);
    if (dis->offset) free(dis->offset);
    if (dis->scale)  free(dis->scale);
d400 1
a400 1
      free(dis->iparm);
d407 1
a407 1
      free(dis->dparm);
d410 2
a411 2
    if (dis->disp2x) free(dis->disp2x);
    if (dis->disx2p) free(dis->disx2p);
d448 1
a448 1
  sizes[0] = sizeof(struct disprm);
d456 1
a456 1
  sizes[1] += naxis * sizeof(char [72]);
d459 1
a459 1
  sizes[1] += dis->ndpmax * sizeof(struct dpkey);
d462 1
a462 1
  sizes[1] += naxis * sizeof(double);
d475 1
a475 1
  sizes[1] += naxis * sizeof(int *);
d478 1
a478 1
  sizes[1] += naxis * sizeof(int *);
d481 2
a482 2
  sizes[1] += naxis * sizeof(int *);
  sizes[1] += naxis*naxis * sizeof(int);
d485 2
a486 2
  sizes[1] += naxis * sizeof(double *);
  sizes[1] += naxis*naxis * sizeof(double);
d489 2
a490 2
  sizes[1] += naxis * sizeof(double *);
  sizes[1] += naxis*naxis * sizeof(double);
d493 1
a493 1
  sizes[1] += naxis * sizeof(int *);
d496 1
a496 1
      sizes[1] += dis->iparm[j][I_NIPARM] * sizeof(int);
d501 1
a501 1
  sizes[1] += naxis * sizeof(double *);
d504 1
a504 1
      sizes[1] += dis->dparm[j][I_NDPARM] * sizeof(double);
d509 1
a509 1
  sizes[1] += naxis * sizeof(int (*)(DISP2X_ARGS));
d512 1
a512 1
  sizes[1] += naxis * sizeof(int (*)(DISX2P_ARGS));
d835 1
d841 3
d846 1
a846 1
      free(dis->axmap);
d848 1
a848 1
      free(dis->offset);
d850 8
a857 1
      free(dis->scale);
d859 2
a860 2
      free(dis->iparm);
      free(dis->dparm);
d862 5
a866 2
      free(dis->disp2x);
      free(dis->disx2p);
d869 1
a869 1
    if ((dis->docorr = calloc(naxis, sizeof(int *))) == 0x0) {
d874 1
a874 1
    if ((dis->Nhat = calloc(naxis, sizeof(int *))) == 0x0) {
d880 1
a880 1
    if ((dis->axmap = calloc(naxis, sizeof(int *))) == 0x0) {
d885 1
a885 1
    if ((dis->axmap[0] = calloc(naxis*naxis, sizeof(int))) == 0x0) {
d895 1
a895 1
    if ((dis->offset = calloc(naxis, sizeof(double *))) == 0x0) {
d900 1
a900 1
    if ((dis->offset[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
d910 1
a910 1
    if ((dis->scale = calloc(naxis, sizeof(double *))) == 0x0) {
d915 1
a915 1
    if ((dis->scale[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
d924 1
a924 1
    if ((dis->iparm = calloc(naxis, sizeof(int *))) == 0x0) {
d929 1
a929 1
    if ((dis->dparm = calloc(naxis, sizeof(double *))) == 0x0) {
d934 2
a935 1
    if ((dis->disp2x = calloc(naxis, sizeof(int (*)(DISP2X_ARGS)))) == 0x0) {
d940 2
a941 1
    if ((dis->disx2p = calloc(naxis, sizeof(int (*)(DISX2P_ARGS)))) == 0x0) {
d954 1
a954 1
  memset(dis->Nhat, 0, naxis*sizeof(int));
d960 1
a960 1
  memset(dis->offset[0], 0, naxis*naxis*sizeof(double));
d971 2
a972 2
  memset(dis->disp2x, 0, naxis*sizeof(int (*)(DISP2X_ARGS)));
  memset(dis->disx2p, 0, naxis*sizeof(int (*)(DISX2P_ARGS)));
d1001 1
a1001 1
    if (strncmp(fp, "DOCORR", 7) == 0) {
d1006 1
a1006 1
    } else if (strncmp(fp, "NAXES", 6) == 0) {
d1274 1
a1274 1
  if ((tmpmem = calloc(5*naxis, sizeof(double))) == 0x0) {
a1502 6
    } else if (pixsamp[j] == 0.0) {
      pixinc[j] = 1.0;
    } else if (pixsamp[j] > 0.0) {
      pixinc[j] = pixsamp[j];
    } else if (pixsamp[j] > -1.5) {
      pixinc[j] = 2.0*pixspan;
d1504 9
a1512 1
      pixinc[j] = pixspan / ((int)(-pixsamp[j] - 0.5));
d1542 1
a1542 1
  int carry = 0;
d1550 1
a1550 1
    (*nsamp)++;
d1590 2
d1593 2
a1594 2
    ssqdis[j] /= *nsamp;
    sumdis[j] /= *nsamp;
d1599 2
a1600 2
  ssqtot /= *nsamp;
  sumtot /= *nsamp;
d1616 1
a1616 1
int polyset(int j, struct disprm *dis)
d1627 2
a1628 2
  char   id[32];
  sprintf(id, "Polynomial on axis %d", j+1);
d1843 7
a1849 7
    } else if (strcmp(fp, "DOCORR") &&
               strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6) &&
               strcmp(fp, "NAUX")   &&
               strcmp(fp, "NTERMS")) {
d1934 1
a1934 1
int tpdset(int j, struct disprm *dis)
d1943 1
a1943 1
  sprintf(id, "TPD on axis %d", j+1);
d1997 5
a2001 5
    } else if (strcmp(fp, "DOCORR") &&
               strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
d2160 1
a2160 1
int pol2tpd(int j, struct disprm *dis)
d2231 1
d2271 3
d2305 1
d2330 3
d2363 1
a2363 1
int tpvset(int j, struct disprm *dis)
d2374 1
a2374 1
  sprintf(id, "TPV on axis %d", j+1);
d2410 4
a2413 4
    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
d2503 1
a2503 1
int sipset(int j, struct disprm *dis)
d2525 1
a2525 1
  sprintf(id, "SIP on axis %d", j+1);
d2570 4
a2573 4
    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
d2612 4
d2685 1
a2685 1
int dssset(int j, struct disprm *dis)
d2696 1
a2696 1
  sprintf(id, "DSS on axis %d", j+1);
d2868 4
a2871 4
    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
d2893 1
a2893 1
int watset(int j, struct disprm *dis)
d2915 1
a2915 1
  sprintf(id, "WAT (%s) on axis %d", dis->dtype[0]+4, j+1);
d2973 4
a2976 4
    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
d3115 1
d3117 4
a3120 1
        cheleg(kind, m, n, coeffm, coeffn);
d3142 1
a3142 1
int cheleg(int kind, int m, int n, double coeffm[], double coeffn[])
d3145 4
a3148 1
  int N = (m > n) ? m : n;
d3151 5
a3155 2
  double *coeff[3];
  coeff[0] = calloc(3*(N+1), sizeof(double));
d3160 1
a3160 1
    int j0 =  j%3;
d3191 1
a3191 1
  free(coeff[0]);
d3198 1
a3198 1
int dispoly(
d3223 2
a3224 2
    const double *cptr = dparm + k*iparm[I_NKPARM];
    const double *pptr = cptr + (1+Nhat);
d3227 1
a3227 1
    double auxp0  = *(pptr++);
d3311 1
a3311 1
int tpd1(
d3358 1
a3358 1
int tpd2(
d3407 1
a3407 1
int tpd3(
d3457 1
a3457 1
int tpd4(
d3508 1
a3508 1
int tpd5(
d3560 1
a3560 1
int tpd6(
d3613 1
a3613 1
int tpd7(
d3667 1
a3667 1
int tpd8(
d3722 1
a3722 1
int tpd9(
@


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


8.6.1.2
log
@Include wcslimits.h to get NAXMAX.  NDPMAX is now also declared in
wcslimits.h and set in wcs.c.  In disinit(), return DISERR_BAD_PARAM rather
than DISERR_MEMORY if naxis is negative.
Inconsequential change prompted by clang-tidy:
 - In disinit(), check that naxis does not exceed NAXMAX
   (bugprone-implicit-widening-of-multiplication-result).
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.1 2026/03/29 14:19:26 mcalabre Exp mcalabre $
a30 1
#include "wcslimits.h"
d35 3
a221 1
  // Sanity check on naxis.
d223 1
a223 1
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
a224 5
  }

  if (NAXMAX < naxis) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "naxis exceeds %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.strcpy).
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.2 2026/04/05 08:23:54 mcalabre Exp mcalabre $
d103 1
a103 1
          snprintf(dp->field, 72, "%s%d.%s", keyword, j, field);
d107 2
a108 2
          snprintf(dp->field, 72, "%s.%s", keyword, field);
          snprintf(axno, 8, "%d", j);
d113 1
a113 1
        snprintf(dp->field, 72, "%s.%s", keyword, field);
d116 1
a116 1
      strncpy(dp->field, keyword, 72);
d119 1
a119 1
    strncpy(dp->field, field, 72);
d1604 2
a1605 2
  char id[32];
  snprintf(id, 32, "Polynomial on axis %d", j+1);
d1920 1
a1920 1
  snprintf(id, 32, "TPD on axis %d", j+1);
d2343 1
a2343 1
  snprintf(id, 32, "TPV on axis %d", j+1);
d2494 1
a2494 1
  snprintf(id, 32, "SIP on axis %d", j+1);
d2661 1
a2661 1
  snprintf(id, 32, "DSS on axis %d", j+1);
d2880 1
a2880 1
  snprintf(id, 32, "WAT (%s) on axis %d", dis->dtype[0]+4, j+1);
@


8.6.1.4
log
@Found by clang-tidy:
 - In disset(), after freeing memory for derived parameter and work arrays in
   disprm, set the relevant pointers to zero to prevent possible double-free
   in disfree() if memory allocation fails (clang-analyzer-unix.Malloc).
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.3 2026/04/10 03:40:30 mcalabre Exp mcalabre $
a836 3
      dis->docorr = 0x0;
      dis->Nhat   = 0x0;

a844 4
      dis->axmap  = 0x0;
      dis->offset = 0x0;
      dis->scale  = 0x0;

a847 3
      dis->iparm  = 0x0;
      dis->dparm  = 0x0;

a849 3

      dis->disp2x = 0x0;
      dis->disx2p = 0x0;
@


8.6.1.5
log
@Found by clang-tidy:
 - In discpy(), guard against disdst->dp == 0x0, which can happen in disinit()
   if ndpmax == 0 (clang-analyzer-core.NonNullParamChecker).
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.4 2026/04/12 07:04:13 mcalabre Exp mcalabre $
d353 1
a353 3
  if (disdst->dp) {
    memcpy(disdst->dp, dissrc->dp, dissrc->ndpmax*sizeof(struct dpkey));
  }
@


8.6.1.6
log
@Found by clang-tidy:
 - In disset(), fixed the calculation of the amount of memory required for
   disprm::docorr and disprm::Nhat.  The calculation used sizeof(int *) rather
   than sizeof(int) (clang-analyzer-unix.MallocSizeof).
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.5 2026/04/12 07:40:09 mcalabre Exp mcalabre $
d867 1
a867 1
    if ((dis->docorr = calloc(naxis, sizeof(int))) == 0x0) {
d872 1
a872 1
    if ((dis->Nhat = calloc(naxis, sizeof(int))) == 0x0) {
@


8.6.1.7
log
@Declare helper functions static when defined (in addition to their initial
declaration).
Found by clang-tidy:
 - In pol2tpd() and sipset(), ensure ndparm != 0 when calling calloc()
   (clang-analyzer-optin.portability.UnixAPI).
Found by cppcheck:
 - In cheleg(), ensure that memory allocation succeeded.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.6 2026/04/12 07:47:35 mcalabre Exp mcalabre $
d1608 1
a1608 1
static int polyset(int j, struct disprm *dis)
d1926 1
a1926 1
static int tpdset(int j, struct disprm *dis)
d2152 1
a2152 1
static int pol2tpd(int j, struct disprm *dis)
a2222 1
        if (9 < deg)    return -1;
a2261 3
  } else {
    // Can't happen; this is just to appease clang-tidy.
    return -1;
d2347 1
a2347 1
static int tpvset(int j, struct disprm *dis)
d2487 1
a2487 1
static int sipset(int j, struct disprm *dis)
a2595 4
    } else {
      // Can't happen; this is just to appease clang-tidy.
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Degree must not exceed 9, got %d", degree[idis]);
d2665 1
a2665 1
static int dssset(int j, struct disprm *dis)
d2873 1
a2873 1
static int watset(int j, struct disprm *dis)
d3118 1
a3118 1
static int cheleg(int kind, int m, int n, double coeffm[], double coeffn[])
d3124 2
a3125 5
  double *coeff[3], *dp;
  if ((dp = calloc(3*(N+1), sizeof(double))) == 0x0) {
    return 1;
  }
  coeff[0] = dp;
d3130 1
a3130 1
    int j0 = j%3;
d3161 1
a3161 1
  free(dp);
d3168 1
a3168 1
static int dispoly(
d3281 1
a3281 1
static int tpd1(
d3328 1
a3328 1
static int tpd2(
d3377 1
a3377 1
static int tpd3(
d3427 1
a3427 1
static int tpd4(
d3478 1
a3478 1
static int tpd5(
d3530 1
a3530 1
static int tpd6(
d3583 1
a3583 1
static int tpd7(
d3637 1
a3637 1
static int tpd8(
d3692 1
a3692 1
static int tpd9(
@


8.6.1.8
log
@Found by clang-tidy:
 - In diswarp(), guard against dereferencing nsamp, which may be given as a
   NULL pointer (clang-analyzer-core.NullDereference).
 - Prevent a memory leak on error return from pol2tpd()
   (clang-analyzer-unix.Malloc).
Further inconsequential changes prompted by clang-tidy:
 - In diswarp(), restructured an if-block to disguise a repetition
   (bugprone-branch-clone).
 - Use size_t for memory address and size calculations and allocation
   (bugprone-implicit-widening-of-multiplication-result).
 - Explicitly cast pointers-to-pointers returned from calloc() or used as 
   arguments to free() (bugprone-multi-level-implicit-pointer-conversion).
 - 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 strcmp() and strncmp() in if-statements
   (bugprone-suspicious-string-compare).
 - Added a default case (empty) to a switch statement in pol2tpd()
   (bugprone-switch-missing-default-case).
 - Added checks on inputs to cheleg() just to keep clang-tidy happy
   (clang-analyzer-core.UndefinedBinaryOperatorResult).
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.7 2026/04/12 11:33:34 mcalabre Exp mcalabre $
a26 1
#include <stddef.h>
d391 3
a393 3
    if (dis->axmap)  free((void *)dis->axmap);
    if (dis->offset) free((void *)dis->offset);
    if (dis->scale)  free((void *)dis->scale);
d399 1
a399 1
      free((void *)dis->iparm);
d406 1
a406 1
      free((void *)dis->dparm);
d409 2
a410 2
    if (dis->disp2x) free((void *)dis->disp2x);
    if (dis->disx2p) free((void *)dis->disx2p);
d447 1
a447 1
  sizes[0] = (int)sizeof(struct disprm);
d455 1
a455 1
  sizes[1] += naxis * (int)sizeof(char [72]);
d458 1
a458 1
  sizes[1] += dis->ndpmax * (int)sizeof(struct dpkey);
d461 1
a461 1
  sizes[1] += naxis * (int)sizeof(double);
d474 1
a474 1
  sizes[1] += naxis * (int)sizeof(int *);
d477 1
a477 1
  sizes[1] += naxis * (int)sizeof(int *);
d480 2
a481 2
  sizes[1] += naxis * (int)sizeof(int *);
  sizes[1] += naxis*naxis * (int)sizeof(int);
d484 2
a485 2
  sizes[1] += naxis * (int)sizeof(double *);
  sizes[1] += naxis*naxis * (int)sizeof(double);
d488 2
a489 2
  sizes[1] += naxis * (int)sizeof(double *);
  sizes[1] += naxis*naxis * (int)sizeof(double);
d492 1
a492 1
  sizes[1] += naxis * (int)sizeof(int *);
d495 1
a495 1
      sizes[1] += dis->iparm[j][I_NIPARM] * (int)sizeof(int);
d500 1
a500 1
  sizes[1] += naxis * (int)sizeof(double *);
d503 1
a503 1
      sizes[1] += (int)dis->dparm[j][I_NDPARM] * (int)sizeof(double);
d508 1
a508 1
  sizes[1] += naxis * (int)sizeof(int (*)(DISP2X_ARGS));
d511 1
a511 1
  sizes[1] += naxis * (int)sizeof(int (*)(DISX2P_ARGS));
a833 1
  size_t naxszt = naxis;
d844 1
a844 1
      free((void *)dis->axmap);
d846 1
a846 1
      free((void *)dis->offset);
d848 1
a848 1
      free((void *)dis->scale);
d854 2
a855 2
      free((void *)dis->iparm);
      free((void *)dis->dparm);
d860 2
a861 2
      free((void *)dis->disp2x);
      free((void *)dis->disx2p);
d867 1
a867 1
    if ((dis->docorr = calloc(naxszt, sizeof(int))) == 0x0) {
d872 1
a872 1
    if ((dis->Nhat = calloc(naxszt, sizeof(int))) == 0x0) {
d878 1
a878 1
    if ((dis->axmap = (int **)calloc(naxszt, sizeof(int *))) == 0x0) {
d883 1
a883 1
    if ((dis->axmap[0] = calloc(naxszt*naxszt, sizeof(int))) == 0x0) {
d893 1
a893 1
    if ((dis->offset = (double **)calloc(naxszt, sizeof(double *))) == 0x0) {
d898 1
a898 1
    if ((dis->offset[0] = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
d908 1
a908 1
    if ((dis->scale = (double **)calloc(naxszt, sizeof(double *))) == 0x0) {
d913 1
a913 1
    if ((dis->scale[0] = calloc(naxszt*naxszt, sizeof(double))) == 0x0) {
d922 1
a922 1
    if ((dis->iparm = (int **)calloc(naxszt, sizeof(int *))) == 0x0) {
d927 1
a927 1
    if ((dis->dparm = (double **)calloc(naxszt, sizeof(double *))) == 0x0) {
d932 1
a932 2
    if ((dis->disp2x = (int (**)(DISP2X_ARGS))calloc(naxszt,
           sizeof(int (*)(DISP2X_ARGS)))) == 0x0) {
d937 1
a937 2
    if ((dis->disx2p = (int (**)(DISX2P_ARGS))calloc(naxszt,
           sizeof(int (*)(DISX2P_ARGS)))) == 0x0) {
d950 1
a950 1
  memset(dis->Nhat, 0, naxszt*sizeof(int));
d956 1
a956 1
  memset(dis->offset[0], 0, naxszt*naxszt*sizeof(double));
d967 2
a968 2
  memset((void *)dis->disp2x, 0, naxis*sizeof(int (*)(DISP2X_ARGS)));
  memset((void *)dis->disx2p, 0, naxis*sizeof(int (*)(DISX2P_ARGS)));
d997 1
a997 1
    if (strcmp(fp, "DOCORR") == 0) {
d1002 1
a1002 1
    } else if (strcmp(fp, "NAXES") == 0) {
d1270 1
a1270 1
  if ((tmpmem = calloc(5*(size_t)naxis, sizeof(double))) == 0x0) {
d1499 6
d1506 1
a1506 9
      if (pixsamp[j] == 0.0) {
        pixinc[j] = 1.0;
      } else if (pixsamp[j] > 0.0) {
        pixinc[j] = pixsamp[j];
      } else if (pixsamp[j] > -1.5) {
        pixinc[j] = 2.0*pixspan;
      } else {
        pixinc[j] = pixspan / ((int)(-pixsamp[j] - 0.5));
      }
d1536 1
a1536 1
  int carry = 0, count = 0;
d1544 1
a1544 1
    count++;
a1583 2
  if (nsamp) *nsamp = count;

d1585 2
a1586 2
    ssqdis[j] /= count;
    sumdis[j] /= count;
d1591 2
a1592 2
  ssqtot /= count;
  sumtot /= count;
d1835 7
a1841 7
    } else if (strcmp(fp, "DOCORR") != 0 &&
               strcmp(fp, "NAXES")  != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0 &&
               strcmp(fp, "NAUX")   != 0 &&
               strcmp(fp, "NTERMS") != 0) {
d1989 5
a1993 5
    } else if (strcmp(fp, "DOCORR") != 0 &&
               strcmp(fp, "NAXES")  != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
a2296 1
    free(tpd_iparm);
a2320 2
      default:
        // Nothing.
d2398 4
a2401 4
    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
d2558 4
a2561 4
    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
d2856 4
a2859 4
    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
d2961 4
a2964 4
    } else if (strcmp(fp, "NAXES") != 0 &&
              strncmp(fp, "AXIS.",   5) != 0 &&
              strncmp(fp, "OFFSET.", 7) != 0 &&
              strncmp(fp, "SCALE.",  6) != 0) {
a3102 1
        int status;
d3104 1
a3104 4
        if ((status = cheleg(kind, m, n, coeffm, coeffn))) {
          return wcserr_set(DIS_ERRMSG(status));
        }

d3129 1
a3129 4
  int N = (n < m) ? m : n;
  if (N < 0) {
    return DISERR_BAD_PARAM;
  }
d3133 2
a3134 2
  if ((dp = calloc(3*(size_t)(N+1), sizeof(double))) == 0x0) {
    return DISERR_MEMORY;
d3204 2
a3205 2
    const double *cptr = dparm + (ptrdiff_t)(k*iparm[I_NKPARM]);
    const double *pptr = cptr  + (ptrdiff_t)(1+Nhat);
d3208 1
a3208 1
    double auxp0 = *(pptr++);
@


8.6.1.9
log
@Appeased a pedantic compiler warning.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.6.1.8 2026/04/21 14:13:40 mcalabre Exp mcalabre $
a2331 1
        break;
@


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


8.5.1.1
log
@WCSLIB 8.5 development branch.
@
text
@d22 1
a22 1
  $Id: dis.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: dis.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: dis.c,v 8.3.1.2 2024/07/09 08:23:44 mcalabre Exp mcalabre $
@


8.4.1.1
log
@WCSLIB 8.4 development branch.
@
text
@d22 1
a22 1
  $Id: dis.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: dis.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: dis.c,v 8.2.1.8 2024/05/10 14:31:08 mcalabre Exp mcalabre $
d669 1
a669 1
  // Work arrays.
d700 1
a700 1
  // Pointers to distortion functions.
a777 3
  int naxis = dis->naxis;


d784 2
a785 1
  int ndis = 0;
@


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


8.3.1.2
log
@Trivia.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.3.1.1 2024/05/13 16:35:39 mcalabre Exp mcalabre $
d669 1
a669 1
  // Pointers to distortion functions.
d700 1
a700 1
  // Pointers to inverse distortion functions.
d778 3
d787 1
a787 2
  int naxis = dis->naxis;
  int ndis  = 0;
@


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: dis.c,v 8.1.1.1 2023/07/05 17:15:00 mcalabre Exp mcalabre $
a34 6
const int DISSET = 137;

const int DIS_TPD        =    1;
const int DIS_POLYNOMIAL =    2;
const int DIS_DOTPD      = 1024;

d47 5
a51 2
// Convenience macro for invoking wcserr_set().
#define DIS_ERRMSG(status) WCSERR_SET(status), dis_errmsg[status]
d81 3
d140 1
a140 1
  return DISERR_SUCCESS;
a301 1
  dis->flag  = 0;
d318 3
a320 1
  return DISERR_SUCCESS;
d354 1
a354 1
  return DISERR_SUCCESS;
d427 1
a427 1
  return DISERR_SUCCESS;
d463 2
a464 2
  if (dis->flag != DISSET) {
    return DISERR_SUCCESS;
d507 29
a535 1
  return DISERR_SUCCESS;
d545 1
a545 1
  if (dis->flag != DISSET) {
d547 1
a547 1
    return DISERR_SUCCESS;
d553 1
a554 2

  // Parameters supplied.
d699 2
d720 1
a720 1
  return DISERR_SUCCESS;
d734 1
a734 1
  return DISERR_SUCCESS;
d775 1
a1141 1
  dis->flag = DISSET;
d1143 3
a1145 1
  return DISERR_SUCCESS;
d1162 2
a1163 2
  int status = DISERR_SUCCESS;
  if (dis->flag != DISSET) {
d1245 2
a1246 2
  int status = DISERR_SUCCESS;
  if (dis->flag != DISSET) {
d1311 1
a1311 1
  int convergence, iter;
d1462 1
a1462 1
  if (dis->ndis == 0) return DISERR_SUCCESS;
d1465 1
a1465 1
  if ((tmpmem = calloc(4*naxis, sizeof(double))) == 0x0) {
d1495 1
a1495 1
  if ((pix0 = calloc(2*naxis, sizeof(double))) == 0x0) {
@


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


8.2.1.2
log
@Declared DISSET, DIS_TPD, DIS_POLYNOMIAL, and DIS_DOTPD to be static.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.2.1.1 2023/11/16 10:05:57 mcalabre Exp mcalabre $
d35 6
d53 2
a54 5
static const int DISSET = 137;

static const int DIS_TPD        =    1;
static const int DIS_POLYNOMIAL =    2;
static const int DIS_DOTPD      = 1024;
a82 3

// Convenience macro for invoking wcserr_set().
#define DIS_ERRMSG(status) WCSERR_SET(status), dis_errmsg[status]
@


8.2.1.3
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2024, Mark Calabretta
d22 1
a22 1
  $Id: dis.c,v 8.2.1.2 2023/11/29 07:43:49 mcalabre Exp mcalabre $
d1279 1
a1279 1
  int convergence = 0, iter;
@


8.2.1.4
log
@In diswarp(), cast the first argument to size_t in the calls to calloc() to
avoid a mystifying compiler warning.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.2.1.3 2024/04/02 14:01:58 mcalabre Exp mcalabre $
d1433 1
a1433 1
  if ((tmpmem = calloc(4*(size_t)naxis, sizeof(double))) == 0x0) {
d1463 1
a1463 1
  if ((pix0 = calloc(2*(size_t)naxis, sizeof(double))) == 0x0) {
@


8.2.1.5
log
@Changes required to support bypass mode in disset().
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.2.1.4 2024/05/05 04:41:03 mcalabre Exp mcalabre $
d140 1
a140 1
  return 0;
d302 1
d319 1
a319 3
  dis->flag = 0;

  return 0;
d353 1
a353 1
  return 0;
d426 1
a426 1
  return 0;
d462 2
a463 2
  if (abs(dis->flag) != DISSET) {
    return 0;
d506 1
a506 1
  return 0;
d516 1
a516 1
  if (abs(dis->flag) != DISSET) {
d518 1
a518 1
    return 0;
d524 2
a526 1
  wcsprintf("       flag: %d\n", dis->flag);
a670 2

  // Pointers to distortion functions.
d690 1
a690 1
  return 0;
d704 1
a704 1
  return 0;
a744 1
  if (dis->flag == -DISSET) return 0;
d1111 1
d1113 1
a1113 3
  dis->flag = (dis->flag == 1) ? -DISSET : DISSET;

  return 0;
d1130 2
a1131 2
  int status = 0;
  if (abs(dis->flag) != DISSET) {
d1213 2
a1214 2
  int status = 0;
  if (abs(dis->flag) != DISSET) {
d1430 1
a1430 1
  if (dis->ndis == 0) return 0;
@


8.2.1.6
log
@Added disenq().
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.2.1.5 2024/05/08 08:49:36 mcalabre Exp mcalabre $
a507 30
}

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

int disenq(const struct disprm *dis, int enquiry)

{
  static const char *function = "disenq";

  // Initialize.
  if (dis == 0x0) return DISERR_NULL_POINTER;

  int answer = 0;

  if (enquiry & DISENQ_MEM) {
    if (dis->m_flag != DISSET) return 0;
    answer = 1;
  }

  if (enquiry & DISENQ_SET) {
    if (abs(dis->flag) != DISSET) return 0;
    answer = 1;
  }

  if (enquiry & DISENQ_BYP) {
    if (dis->flag != -DISSET) return 0;
    answer = 1;
  }

  return answer;
@


8.2.1.7
log
@Attended to compiler warnings about unused variables.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.2.1.6 2024/05/08 15:13:53 mcalabre Exp mcalabre $
d515 2
@


8.2.1.8
log
@In disenq(), the disprm struct is also in bypass mode, though unset, if
disprm::flag == 1.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.2.1.7 2024/05/08 15:39:34 mcalabre Exp mcalabre $
d531 1
a531 1
    if (dis->flag != 1 && dis->flag != -DISSET) return 0;
@


8.1
log
@WCSLIB 8.1
@
text
@d2 1
a2 1
  WCSLIB 8.1 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: dis.c,v 8.0.1.2 2023/07/04 08:59:35 mcalabre Exp mcalabre $
@


8.1.1.1
log
@WCSLIB 8.1 development branch.
@
text
@d22 1
a22 1
  $Id: dis.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: dis.c,v 7.13.1.2 2023/06/15 04:17:19 mcalabre Exp mcalabre $
a209 1
      dis->dummy  = 0x0;
d314 1
a317 1
  dis->totdis = 0.0;
d350 1
a351 1
  disdst->totdis = dissrc->totdis;
d547 2
a554 2

  wcsprintf("     totdis:  %#- 11.5g\n", dis->totdis);
@


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


8.0.1.2
log
@Changed the order of maxdis and totdis in disprm to ensure correct
alignment of doubles on 32-bit machines.
@
text
@d22 1
a22 1
  $Id: dis.c,v 8.0.1.1 2023/07/01 06:22:44 mcalabre Exp mcalabre $
d210 1
a314 1
  dis->totdis = 0.0;
d318 1
d351 1
a352 1
  memcpy(disdst->maxdis, dissrc->maxdis, naxis*sizeof(double));
a547 2
  wcsprintf("     totdis:  %#- 11.5g\n", dis->totdis);

d554 2
@


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: dis.c,v 7.12.1.3 2022/10/07 03:29:36 mcalabre Exp mcalabre $
@


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


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


7.12
log
@WCSLIB 7.12
@
text
@d2 1
a2 1
  WCSLIB 7.12 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: dis.c,v 7.11.1.1 2022/04/26 06:15:32 mcalabre Exp mcalabre $
d140 1
a140 1
  return 0;
d210 1
a210 1
      dis->tmpmem = 0x0;
d320 1
a320 1
  return 0;
d354 1
a354 1
  return 0;
a404 1
    if (dis->tmpmem) free(dis->tmpmem);
a421 1
  dis->tmpmem = 0x0;
d427 1
a427 1
  return 0;
a506 3
  // dis::tmpmem[].
  sizes[1] += 5*naxis * sizeof(double);

d519 1
a519 1
    return 0;
a676 1
  WCSPRINTF_PTR("     tmpmem: ", dis->tmpmem, "\n");
d691 1
a691 1
  return 0;
d705 1
a705 1
  return 0;
a817 2

      free(dis->tmpmem);
a894 5
    if ((dis->tmpmem = calloc(5*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

a921 1
  memset(dis->tmpmem, 0, naxis*sizeof(double));
d1114 1
a1114 1
  return 0;
d1131 1
a1132 1
    int status;
d1138 6
a1145 1
  double *tmpcrd = dis->tmpmem;
d1160 2
a1161 1
        return wcserr_set(DIS_ERRMSG(DISERR_DISTORT));
d1177 3
a1179 1
  return 0;
a1209 2
  int status;

d1214 5
d1221 12
a1232 5
  // Carve up working memory, noting that disp2x() gets to it first.
  double *dcrd0 = dis->tmpmem + naxis;
  double *dcrd1 = dcrd0 + naxis;
  double *rcrd1 = dcrd1 + naxis;
  double *delta = rcrd1 + naxis;
a1247 1
      double *tmpcrd = dis->tmpmem;
d1258 2
a1259 1
        return wcserr_set(DIS_ERRMSG(DISERR_DEDISTORT));
d1275 1
a1275 1
    return 0;
d1283 2
a1284 1
      return wcserr_set(DIS_ERRMSG(status));
d1340 2
a1341 1
        return wcserr_set(DIS_ERRMSG(status));
d1360 2
a1361 1
          return wcserr_set(DIS_ERRMSG(status));
d1382 1
a1382 1
    return wcserr_set(WCSERR_SET(DISERR_DEDISTORT),
d1385 1
d1389 3
a1391 1
  return 0;
d1431 7
a1437 1
  if (dis->ndis == 0) return 0;
d1439 2
a1440 2
  // Carve up working memory, noting that disp2x() gets to it first.
  double *pixinc = dis->tmpmem + naxis;
d1465 2
a1466 1
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d1550 4
a1553 1
  free(pix0);
@


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


7.12.1.2
log
@Using disprm::tmpmem as temporary storage space for calculations runs foul
of thread safety.
@
text
@d22 1
a22 1
  $Id: dis.c,v 7.12.1.1 2022/09/09 05:00:36 mcalabre Exp mcalabre $
d140 1
a140 1
  return DISERR_SUCCESS;
d210 1
a210 1
      dis->dummy  = 0x0;
d320 1
a320 1
  return DISERR_SUCCESS;
d354 1
a354 1
  return DISERR_SUCCESS;
d405 1
d423 1
d429 1
a429 1
  return DISERR_SUCCESS;
d509 3
d524 1
a524 1
    return DISERR_SUCCESS;
d682 1
d697 1
a697 1
  return DISERR_SUCCESS;
d711 1
a711 1
  return DISERR_SUCCESS;
d824 2
d903 5
d935 1
d1128 1
a1128 1
  return DISERR_SUCCESS;
a1140 2
  int status;

d1146 1
a1151 5
  double *tmpcrd;
  if ((tmpcrd = calloc(naxis, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

d1154 1
d1169 1
a1169 2
        status = wcserr_set(DIS_ERRMSG(DISERR_DISTORT));
        goto cleanup;
d1185 1
a1185 3
cleanup:
  if (tmpcrd) free(tmpcrd);
  return status;
d1216 1
a1216 1
  int status = DISERR_SUCCESS;
d1224 5
a1228 11
  double *tmpmem;
  if ((tmpmem = calloc(5*naxis, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  // Carve up working memory.
  double *tmpcrd = tmpmem;
  double *dcrd0  = tmpcrd + naxis;
  double *dcrd1  = dcrd0  + naxis;
  double *rcrd1  = dcrd1  + naxis;
  double *delta  = rcrd1  + naxis;
d1244 1
d1255 1
a1255 2
        status = wcserr_set(DIS_ERRMSG(DISERR_DEDISTORT));
        goto cleanup;
d1271 1
a1271 1
    goto cleanup;
d1279 1
a1279 2
      wcserr_set(DIS_ERRMSG(status));
      goto cleanup;
d1335 1
a1335 2
        wcserr_set(DIS_ERRMSG(status));
        goto cleanup;
d1354 1
a1354 2
          wcserr_set(DIS_ERRMSG(status));
          goto cleanup;
d1375 1
a1375 1
    status = wcserr_set(WCSERR_SET(DISERR_DEDISTORT),
a1377 1
    goto cleanup;
d1381 1
a1381 3
cleanup:
  if (tmpmem) free(tmpmem);
  return status;
d1421 1
a1421 6
  if (dis->ndis == 0) return DISERR_SUCCESS;

  double *tmpmem;
  if ((tmpmem = calloc(4*naxis, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }
d1423 2
a1424 2
  // Carve up working memory.
  double *pixinc = tmpmem;
@


7.12.1.3
log
@Continuation of previous change.  Also, in disx2p(), invoke disset() if
necessary.
@
text
@d22 1
a22 1
  $Id: dis.c,v 7.12.1.2 2022/10/06 04:17:53 mcalabre Exp mcalabre $
d1127 2
a1132 1
  int status = DISERR_SUCCESS;
d1141 1
a1141 2
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
d1210 2
a1215 5
  int status = DISERR_SUCCESS;
  if (dis->flag != DISSET) {
    if ((status = disset(dis))) return status;
  }

d1220 1
a1220 2
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
d1431 1
a1431 2
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
d1460 1
a1460 2
    status = wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    goto cleanup;
d1544 1
a1544 4
  if (tmpmem) {
    free(tmpmem);
    if (pix0) free(pix0);
  }
@


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: dis.c,v 7.10.1.1 2022/04/23 14:26:54 mcalabre Exp mcalabre $
@


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


7.10
log
@WCSLIB 7.10
@
text
@d2 1
a2 1
  WCSLIB 7.10 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: dis.c,v 7.9.1.1 2022/03/25 15:16:40 mcalabre Exp mcalabre $
@


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


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: dis.c,v 7.8.1.1 2022/03/25 06:14:14 mcalabre Exp mcalabre $
@


7.9.1.1
log
@WCSLIB 7.9 development branch.
@
text
@d22 1
a22 1
  $Id: dis.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: dis.c,v 7.7.1.2 2022/03/25 06:05:58 mcalabre Exp mcalabre $
@


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


7.7
log
@WCSLIB 7.7
@
text
@d2 2
a3 2
  WCSLIB 7.7 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2021, Mark Calabretta
d22 1
a22 1
  $Id: dis.c,v 7.6.1.3 2021/06/30 16:43:58 mcalabre Exp mcalabre $
@


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


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


7.6
log
@WCSLIB 7.6
@
text
@d2 1
a2 1
  WCSLIB 7.6 - an implementation of the FITS WCS standard.
d22 1
a22 1
  $Id: dis.c,v 7.5.1.2 2021/04/13 09:19:46 mcalabre Exp mcalabre $
a99 2
  char axno[8], *cp;

d108 1
d128 1
a181 2
  struct wcserr **err;

d192 1
a192 1
  err = &(dis->err);
a330 3
  int naxis, status;
  struct wcserr **err;

d333 1
a333 1
  err = &(disdst->err);
d335 1
a335 1
  naxis = dissrc->naxis;
d341 1
a361 2
  int j;

d388 13
a400 3
    for (j = 0; j < dis->i_naxis; j++) {
      if (dis->iparm[j]) free(dis->iparm[j]);
      if (dis->dparm[j]) free(dis->dparm[j]);
a401 2
    if (dis->iparm)  free(dis->iparm);
    if (dis->dparm)  free(dis->dparm);
a447 1
  int exsizes[2];
d460 1
a519 3
  char hext[32];
  int i, j, jhat, k, naxis;

d527 1
a527 1
  naxis = dis->naxis;
d536 1
a536 1
  for (j = 0; j < naxis; j++) {
d543 1
a543 1
  for (i = 0; i < dis->ndp; i++) {
d555 1
a555 1
  for (j = 0; j < naxis; j++) {
d565 1
a565 1
  for (j = 0; j < naxis; j++) {
d572 1
a572 1
  for (j = 0; j < naxis; j++) {
d578 1
a578 1
  for (j = 0; j < naxis; j++) {
d580 1
a580 1
    for (jhat = 0; jhat < naxis; jhat++) {
d587 1
a587 1
  for (j = 0; j < naxis; j++) {
d589 1
a589 1
    for (jhat = 0; jhat < naxis; jhat++) {
d596 1
a596 1
  for (j = 0; j < naxis; j++) {
d598 1
a598 1
    for (jhat = 0; jhat < naxis; jhat++) {
d605 1
a605 1
  for (j = 0; j < naxis; j++) {
d611 1
a611 1
      for (k = 0; k < dis->iparm[j][I_NIPARM]; k++) {
d622 1
a622 1
  for (j = 0; j < naxis; j++) {
d628 1
a628 1
      for (k = 0; k < dis->iparm[j][I_NDPARM]; k++) {
d648 1
d650 1
a650 1
  for (j = 0; j < naxis; j++) {
d678 1
a678 1
  for (j = 0; j < naxis; j++) {
a720 3
  int j, status;
  struct wcserr **err;

d722 1
a722 1
  err = &(dis->err);
d724 2
a725 2
  status = 0;
  for (j = 0; j < dis->naxis; j++) {
a750 5
  char   *dpq, *fp;
  int    idp, j, jhat, k, naxis, ndis, Nhat, status;
  struct dpkey *keyp;
  struct wcserr **err;

d752 1
a752 1
  err = &(dis->err);
d754 1
a754 1
  naxis = dis->naxis;
d763 2
a764 2
  ndis = 0;
  for (j = 0; j < naxis; j++) {
d771 1
d797 1
a797 1
  for (j = 0; j < dis->i_naxis; j++) {
d800 2
d849 1
a849 1
    for (j = 1; j < naxis; j++) {
d864 1
a864 1
    for (j = 1; j < naxis; j++) {
d879 1
a879 1
    for (j = 1; j < naxis; j++) {
d912 1
a912 1
  for (j = 0; j < naxis; j++) {
d918 1
a918 1
  for (jhat = 0; jhat < naxis*naxis; jhat++) {
d924 1
a924 1
  for (jhat = 0; jhat < naxis*naxis; jhat++) {
d939 2
a940 2
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d947 1
a947 1
    j = keyp->j;
d954 1
d970 1
a970 1
      Nhat = dpkeyi(keyp);
d980 1
d992 1
d997 1
d1004 1
a1004 1
  for (j = 0; j < naxis; j++) {
d1008 1
a1008 1
      for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d1027 2
a1028 2
    Nhat = dis->Nhat[j];
    for (jhat = 0; jhat < Nhat; jhat++) {
d1036 1
a1036 1
    for (jhat = 0; jhat < naxis; jhat++) {
d1047 2
a1048 2
    for (jhat = 0; jhat < Nhat; jhat++) {
      for (k = 0; k < jhat; k++) {
d1061 1
a1061 1
  for (j = 0; j < naxis; j++) {
d1073 1
a1140 5
  int    axisj, j, jhat, naxis, Nhat, status;
  double dtmp, *offset, *scale, *tmpcrd;
  struct wcserr **err;


d1143 1
a1143 1
  err = &(dis->err);
d1146 1
d1150 1
a1150 1
  naxis = dis->naxis;
d1154 2
a1155 2
  tmpcrd = dis->tmpmem;
  for (j = 0; j < naxis; j++) {
d1157 2
a1158 2
      offset = dis->offset[j];
      scale  = dis->scale[j];
d1160 3
a1162 3
      Nhat = dis->Nhat[j];
      for (jhat = 0; jhat < Nhat; jhat++) {
        axisj = dis->axmap[j][jhat];
d1166 3
a1168 2
      if ((status = (dis->disp2x[j])(0, dis->iparm[j], dis->dparm[j], Nhat,
                                     tmpcrd, &dtmp))) {
d1216 1
a1216 5
  int    axisj, convergence, iter, itermax, j, jhat, naxis, Nhat, status;
  double dd, *dcrd0, *dcrd1, *delta, *offset, residual, *rcrd1, rtmp, *scale,
         *tmpcrd;
  struct wcserr **err;

d1220 1
a1220 1
  err = &(dis->err);
d1222 1
a1222 1
  naxis = dis->naxis;
d1225 4
a1228 4
  dcrd0 = dis->tmpmem + naxis;
  dcrd1 = dcrd0 + naxis;
  rcrd1 = dcrd1 + naxis;
  delta = rcrd1 + naxis;
d1240 1
a1240 1
  for (j = 0; j < naxis; j++) {
d1242 7
a1248 7
      offset = dis->offset[j];
      scale  = dis->scale[j];
      tmpcrd = dis->tmpmem;

      Nhat = dis->Nhat[j];
      for (jhat = 0; jhat < Nhat; jhat++) {
        axisj = dis->axmap[j][jhat];
d1252 1
d1269 1
d1276 1
d1284 1
a1284 1
    for (j = 0; j < naxis; j++) {
d1287 1
d1305 1
a1305 1
    for (j = 0; j < naxis; j++) {
d1329 1
a1329 1
      for (j = 0; j < naxis; j++) {
d1339 1
a1339 1
      for (j = 0; j < naxis; j++) {
d1349 1
a1349 1
      for (j = 0; j < naxis; j++) {
d1368 3
a1370 3
    residual = 0.0;
    for (j = 0; j < naxis; j++) {
      dd = discrd[j] - dcrd0[j] ;
d1402 1
a1402 5
  int carry, j, naxis, status = 0;
  double dpix, dpx2, dssq, *pix0, *pix1, *pixend, *pixinc, pixspan, *ssqdis,
         ssqtot, *sumdis, sumtot, totdis;
  struct wcserr **err;

d1406 1
a1406 1
  err = &(dis->err);
d1408 1
a1408 1
  naxis = dis->naxis;
d1411 1
a1411 1
  for (j = 0; j < naxis; j++) {
d1424 4
a1427 4
  pixinc = dis->tmpmem + naxis;
  pixend = pixinc + naxis;
  sumdis = pixend + naxis;
  ssqdis = sumdis + naxis;
d1430 2
a1431 2
  for (j = 0; j < naxis; j++) {
    pixspan = pixtrc[j] - (pixblc ? pixblc[j] : 1.0);
d1447 1
d1456 1
a1456 1
  for (j = 0; j < naxis; j++) {
d1462 1
a1462 1
  for (j = 0; j < naxis; j++) {
d1466 2
a1467 2
  sumtot = 0.0;
  ssqtot = 0.0;
d1471 1
a1471 1
  carry = 0;
d1481 4
a1484 4
    dssq = 0.0;
    for (j = 0; j < naxis; j++) {
      dpix = pix1[j] - pix0[j];
      dpx2 = dpix*dpix;
d1496 1
a1496 1
    totdis = sqrt(dssq);
d1505 1
a1505 1
    for (j = 0; j < naxis; j++) {
d1519 1
a1519 1
  for (j = 0; j < naxis; j++) {
a1544 8
  char   *fp, id[32];
  int    i, idp, *iparm, ipow, ivar, jhat, k, K, lendp, m, M, naxis, ndparm,
         Nhat, niparm, nKparm, npow, nTparm, nVar, offset;
  double *dparm, *dptr, power;
  struct dpkey *keyp;
  struct wcserr **err;


d1547 1
a1547 1
  err = &(dis->err);
d1549 3
a1551 1
  naxis = dis->naxis;
d1556 4
a1559 4
  K = 0;
  M = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d1562 1
d1586 5
a1590 5
  Nhat = dis->Nhat[j];
  nKparm = 2*(Nhat + 1);
  nVar   = Nhat + K;
  nTparm = 1 + nVar;
  ndparm = K*nKparm + M*nTparm;
d1611 1
a1611 1
  niparm = I_NPOLY + (2 + 2*M)*nVar;
d1614 1
a1614 1
  lendp = ndparm + K;
d1626 2
a1627 2
  iparm = dis->iparm[j];
  dparm = dis->dparm[j];
d1652 3
a1654 3
  dptr = dparm + (1 + Nhat);
  for (k = 0; k < K; k++) {
    for (jhat = 0; jhat <= Nhat; jhat++) {
d1662 1
a1662 1
  for (m = 0; m < M; m++) {
d1668 1
d1671 1
a1671 1
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d1675 1
a1675 1
    fp = strchr(keyp->field, '.') + 1;
d1692 1
d1705 1
d1738 1
d1746 1
a1746 1
        power = dpkeyd(keyp);
d1759 1
a1759 1
        power = dpkeyd(keyp);
d1788 1
a1788 1
  for (ivar = 0; ivar < nVar; ivar++) {
d1794 1
a1794 1
  for (ivar = 0; ivar < nVar; ivar++) {
d1797 1
a1797 1
      power = dparm[i];
d1800 1
a1800 1
      ipow = (int)power;
d1824 2
a1825 2
  npow = 0;
  for (ivar = 0; ivar < nVar; ivar++) {
a1862 6
  char   *fp, id[32];
  int    doaux, doradial, idis, idp, k, m, ncoeff[2], ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);

d1864 1
a1864 1
  err = &(dis->err);
d1866 1
d1878 5
a1882 6
  ncoeff[0] = 0;
  ncoeff[1] = 0;
  doaux     = 0;
  doradial  = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d1885 1
a1885 1
    fp = strchr(keyp->field, '.') + 1;
d1889 1
d1902 1
d1931 2
a1932 3
  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (idis = 0; idis < 2; idis++) {
d1994 1
a1994 1
  niparm = I_NTPD;
d1999 1
a1999 1
  ndparm = (doaux?6:0) + ncoeff[0] + ncoeff[1];
d2029 1
a2029 1
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2032 1
a2032 1
    fp = strchr(keyp->field, '.') + 1;
d2037 1
d2056 1
d2063 1
a2063 1
      idis = 3*(k-1) + m;
d2068 1
a2068 1
      idis = (doaux?6:0);
d2073 1
a2099 5
  int deg, degree, *iflgp, *iparm, *ipowp, jhat, K, m, n, ndparm, Nhat,
      niparm, p[2], *tpd_iparm;
  double *dparm, *dpolp, *tpd_dparm;
  struct wcserr **err;

d2102 1
a2102 1
  err = &(dis->err);
d2104 2
a2105 2
  iparm = dis->iparm[j];
  dparm = dis->dparm[j];
d2109 1
a2109 1
  Nhat = dis->Nhat[j];
d2113 1
a2113 1
  K = iparm[I_K];
d2126 6
a2131 6
  iflgp = iparm + iparm[I_FLAGS];
  ipowp = iparm + iparm[I_IPOW];
  degree = 0;
  for (m = 0; m < iparm[I_M]; m++) {
    deg = 0;
    for (jhat = 0; jhat < Nhat; jhat++) {
d2166 1
a2166 1
  ndparm = 0;
d2200 2
a2201 1
  niparm = I_NTPD;
d2223 1
d2229 2
a2230 2
  dpolp = dparm + iparm[I_DPOLY];
  for (m = 0; m < iparm[I_M]; m++) {
d2253 2
a2254 2
      p[0] = p[1] = 0;
      for (jhat = 0; jhat < Nhat; jhat++) {
d2258 1
a2258 1
      n = map[p[0]][p[1]];
a2283 6
  char   *fp, id[32];
  int    doradial, idp, k, ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;


d2286 1
a2286 1
  err = &(dis->err);
d2289 1
d2302 4
a2305 4
  ndparm   = 0;
  doradial = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2308 1
a2308 1
    fp = strchr(keyp->field, '.') + 1;
d2311 1
d2374 1
a2374 1
  niparm = I_NTPD;
d2401 1
a2401 1
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2404 1
a2404 1
    fp = strchr(keyp->field, '.') + 1;
d2408 1
a2434 7
  char   *fp, id[32];
  int    deg, degree[2], idis, idp, ncoeff[2], ndparm, niparm, p, q;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);


d2437 1
a2437 1
  err = &(dis->err);
d2440 1
d2453 3
a2455 4
  degree[0] =  1;
  degree[1] = -1;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2458 1
a2458 1
    fp = strchr(keyp->field, '.') + 1;
d2462 1
d2476 1
d2478 1
a2478 1
      deg = p + q;
d2498 2
a2499 3
  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (idis = 0; idis < 2; idis++) {
d2538 1
a2538 1
  niparm = I_NTPD;
d2543 1
a2543 1
  ndparm = ncoeff[0] + ncoeff[1];
d2567 1
a2567 1
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2570 1
a2570 1
    fp = strchr(keyp->field, '.') + 1;
d2574 1
d2581 1
a2601 7
  char   *fp, id[32];
  int    degree, idp, m, ncoeff, ndparm, niparm;
  double A1, A2, A3, B1, B2, B3, coeff, *dparm, S, X0, Y0;
  struct dpkey *keyp;
  struct wcserr **err;


d2604 1
a2604 1
  err = &(dis->err);
d2607 1
d2621 1
a2621 1
  ncoeff = 24;
d2629 1
a2629 1
  niparm = I_NTPD;
d2634 1
a2634 1
  ndparm = 6 + ncoeff;
d2659 1
d2662 3
a2664 3
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    fp = strchr(keyp->field, '.') + 1;
d2667 1
d2692 2
a2693 2
  X0 = (A2*B3 - A3*B1) / (A1*B1 - A2*B2);
  Y0 = (A3*B2 - A1*B3) / (A1*B1 - A2*B2);
d2695 1
a2695 1
  S = sqrt(fabs(A1*B1 - A2*B2));
d2702 1
a2702 1
  dparm = dis->dparm[j];
d2725 1
a2725 1
  degree = 3;
d2727 1
a2727 1
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2730 1
a2730 1
    fp = strchr(keyp->field, '.') + 1;
d2734 2
a2735 1
      if ((coeff = dpkeyd(keyp)) == 0.0) continue;
d2738 1
d2774 1
a2774 1
	degree = 5;
a2820 9
  char   *fp, id[32];
  int    deg, degree, doaux, idis, idp, im, in, *iparm, kind, m, n, ncoeff,
         ndparm, niparm;
  double coeff, coeffm[10], coeffn[10], *dparm, dx, dy, x0, xmax, xmin,
         y0, ymax, ymin;
  struct dpkey *keyp;
  struct wcserr **err;


d2823 1
a2823 1
  err = &(dis->err);
d2826 1
d2840 8
a2847 6
  degree = 1;
  kind = 0;
  xmin = xmax = 0.0;
  ymin = ymax = 0.0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d2850 1
a2850 1
    fp = strchr(keyp->field, '.') + 1;
d2859 1
d2861 1
a2861 1
        deg = m + n;
d2894 1
a2894 1
  doaux = (kind == 1 || kind == 2);
d2897 1
a2897 1
  ncoeff = 0;
d2941 1
a2941 1
  niparm = I_NTPD;
d2946 1
a2946 1
  iparm = dis->iparm[j];
d2948 1
a2948 1
  ndparm = 6 + ncoeff;
d2971 1
a2971 1
  dparm = dis->dparm[j];
d2976 2
a2977 2
    x0 = (xmax + xmin)/2.0;
    dx = (xmax - xmin)/2.0;
d2987 2
a2988 2
    y0 = (ymax + ymin)/2.0;
    dy = (ymax - ymin)/2.0;
d3004 1
a3004 1
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
d3007 1
a3007 1
    fp = strchr(keyp->field, '.') + 1;
d3014 1
d3019 1
a3019 1
        idis = map[m][n];
d3025 1
a3025 1
        coeff = dpkeyd(keyp);
d3027 1
d3029 1
a3029 1
        for (im = 0; im <= m; im++) {
d3032 1
a3032 1
          for (in = 0; in <= n; in++) {
d3035 1
a3035 1
            idis = map[im][in];
d3053 1
a3053 4
  int    j, j0, j1, j2, k, N;
  double *coeff[3], d;

  N = (m > n) ? m : n;
d3056 1
d3061 2
a3062 2
  for (j = 0; j <= N; j++) {
    j0 =  j%3;
d3072 2
a3073 2
      j1 = (j-1)%3;
      j2 = (j-2)%3;
d3077 2
a3078 2
      d = (double)j;
      for (k = 0; k < N; k++) {
a3108 5
  const int *iflgp, *imaxp, *imaxpow, *ipowp;
  int    ip, ivar, jhat, k, m;
  const double *cptr, *dpolp, *pptr;
  double *aux, auxp0, *dvarpow, *dpowp, term, var;

d3113 1
a3113 1
  for (jhat = 0; jhat < Nhat; jhat++) {
d3121 1
a3121 1
  aux = (double *)(dparm + iparm[I_DAUX]);
d3124 3
a3126 3
  for (k = 0; k < iparm[I_K]; k++) {
    cptr = dparm + k*iparm[I_NKPARM];
    pptr = cptr + (1+Nhat);
d3129 1
a3129 1
    auxp0  = *(pptr++);
d3131 1
a3131 1
    for (jhat = 0; jhat < Nhat; jhat++) {
d3146 2
a3147 2
  imaxpow = iparm + iparm[I_MAXPOW];
  dvarpow = (double *)(dparm + iparm[I_DVPOW]);
d3149 5
a3153 5
  imaxp = imaxpow;
  dpowp = dvarpow;
  for (jhat = 0; jhat < Nhat; jhat++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
d3159 3
a3161 3
  for (k = 0; k < iparm[I_K]; k++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
d3169 5
a3173 5
  iflgp = iparm + iparm[I_FLAGS];
  ipowp = iparm + iparm[I_IPOW];
  dpolp = dparm + iparm[I_DPOLY];
  for (m = 0; m < iparm[I_M]; m++) {
    term = *(dpolp++);
d3178 1
a3178 1
    for (ivar = 0; ivar < iparm[I_NVAR]; ivar++) {
a3221 2
  double r, s, u, v;

d3226 3
a3228 2
  u = rawcrd[0];
  v = rawcrd[1];
a3268 2
  double r, s, u, v;

d3273 3
a3275 2
  u = rawcrd[0];
  v = rawcrd[1];
a3317 2
  double r, s, u, v;

d3322 3
a3324 2
  u = rawcrd[0];
  v = rawcrd[1];
a3367 2
  double r, s, u, v;

d3372 3
a3374 2
  u = rawcrd[0];
  v = rawcrd[1];
a3418 2
  double r, s, u, v;

d3423 3
a3425 2
  u = rawcrd[0];
  v = rawcrd[1];
a3470 2
  double r, s, u, v;

d3475 3
a3477 2
  u = rawcrd[0];
  v = rawcrd[1];
a3523 2
  double r, s, u, v;

d3528 3
a3530 2
  u = rawcrd[0];
  v = rawcrd[1];
a3577 2
  double r, s, u, v;

d3582 3
a3584 2
  u = rawcrd[0];
  v = rawcrd[1];
a3632 2
  double r, s, u, v;

d3637 3
a3639 2
  u = rawcrd[0];
  v = rawcrd[1];
@


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


7.6.1.2
log
@Converted to C99-style intermingled variable declarations.
@
text
@d22 1
a22 1
  $Id: dis.c,v 7.6.1.1 2021/04/13 13:00:35 mcalabre Exp mcalabre $
d100 2
a109 1
          char axno[8];
a128 1
    char *cp;
d182 2
d194 1
a194 1
  struct wcserr **err = &(dis->err);
d333 3
d338 1
a338 1
  struct wcserr **err = &(disdst->err);
d340 1
a340 1
  int naxis = dissrc->naxis;
a345 1
  int status;
d366 2
d394 1
a394 1
    for (int j = 0; j < dis->i_naxis; j++) {
d446 1
a458 1
  int exsizes[2];
d518 3
d528 1
a528 1
  int naxis = dis->naxis;
d537 1
a537 1
  for (int j = 0; j < naxis; j++) {
d544 1
a544 1
  for (int i = 0; i < dis->ndp; i++) {
d556 1
a556 1
  for (int j = 0; j < naxis; j++) {
d566 1
a566 1
  for (int j = 0; j < naxis; j++) {
d573 1
a573 1
  for (int j = 0; j < naxis; j++) {
d579 1
a579 1
  for (int j = 0; j < naxis; j++) {
d581 1
a581 1
    for (int jhat = 0; jhat < naxis; jhat++) {
d588 1
a588 1
  for (int j = 0; j < naxis; j++) {
d590 1
a590 1
    for (int jhat = 0; jhat < naxis; jhat++) {
d597 1
a597 1
  for (int j = 0; j < naxis; j++) {
d599 1
a599 1
    for (int jhat = 0; jhat < naxis; jhat++) {
d606 1
a606 1
  for (int j = 0; j < naxis; j++) {
d612 1
a612 1
      for (int k = 0; k < dis->iparm[j][I_NIPARM]; k++) {
d623 1
a623 1
  for (int j = 0; j < naxis; j++) {
d629 1
a629 1
      for (int k = 0; k < dis->iparm[j][I_NDPARM]; k++) {
a648 1
  char hext[32];
d650 1
a650 1
  for (int j = 0; j < naxis; j++) {
d678 1
a678 1
  for (int j = 0; j < naxis; j++) {
d721 3
d725 1
a725 1
  struct wcserr **err = &(dis->err);
d727 2
a728 2
  int status = 0;
  for (int j = 0; j < dis->naxis; j++) {
d754 5
d760 1
a760 1
  struct wcserr **err = &(dis->err);
d762 1
a762 1
  int naxis = dis->naxis;
d771 2
a772 2
  int ndis = 0;
  for (int j = 0; j < naxis; j++) {
a778 1
  char *dpq;
d804 1
a804 1
  for (int j = 0; j < dis->i_naxis; j++) {
d854 1
a854 1
    for (int j = 1; j < naxis; j++) {
d869 1
a869 1
    for (int j = 1; j < naxis; j++) {
d884 1
a884 1
    for (int j = 1; j < naxis; j++) {
d917 1
a917 1
  for (int j = 0; j < naxis; j++) {
d923 1
a923 1
  for (int jhat = 0; jhat < naxis*naxis; jhat++) {
d929 1
a929 1
  for (int jhat = 0; jhat < naxis*naxis; jhat++) {
d944 2
a945 2
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d952 1
a952 1
    int j = keyp->j;
a958 1
    char *fp;
d974 1
a974 1
      int Nhat = dpkeyi(keyp);
a983 1
      int jhat;
a994 1
      int jhat;
a998 1
      int jhat;
d1005 1
a1005 1
  for (int j = 0; j < naxis; j++) {
d1009 1
a1009 1
      for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d1028 2
a1029 2
    int Nhat = dis->Nhat[j];
    for (int jhat = 0; jhat < Nhat; jhat++) {
d1037 1
a1037 1
    for (int jhat = 0; jhat < naxis; jhat++) {
d1048 2
a1049 2
    for (int jhat = 0; jhat < Nhat; jhat++) {
      for (int k = 0; k < jhat; k++) {
d1062 1
a1062 1
  for (int j = 0; j < naxis; j++) {
a1073 1
    int status;
d1141 5
d1148 1
a1148 1
  struct wcserr **err = &(dis->err);
a1150 1
    int status;
d1154 1
a1154 1
  int naxis = dis->naxis;
d1158 2
a1159 2
  double *tmpcrd = dis->tmpmem;
  for (int j = 0; j < naxis; j++) {
d1161 2
a1162 2
      double *offset = dis->offset[j];
      double *scale  = dis->scale[j];
d1164 3
a1166 3
      int Nhat = dis->Nhat[j];
      for (int jhat = 0; jhat < Nhat; jhat++) {
        int axisj = dis->axmap[j][jhat];
d1170 2
a1171 3
      double dtmp;
      if ((dis->disp2x[j])(0, dis->iparm[j], dis->dparm[j], Nhat, tmpcrd,
                           &dtmp)) {
d1219 5
a1223 1
  int status;
d1227 1
a1227 1
  struct wcserr **err = &(dis->err);
d1229 1
a1229 1
  int naxis = dis->naxis;
d1232 4
a1235 4
  double *dcrd0 = dis->tmpmem + naxis;
  double *dcrd1 = dcrd0 + naxis;
  double *rcrd1 = dcrd1 + naxis;
  double *delta = rcrd1 + naxis;
d1247 1
a1247 1
  for (int j = 0; j < naxis; j++) {
d1249 7
a1255 7
      double *offset = dis->offset[j];
      double *scale  = dis->scale[j];
      double *tmpcrd = dis->tmpmem;

      int Nhat = dis->Nhat[j];
      for (int jhat = 0; jhat < Nhat; jhat++) {
        int axisj = dis->axmap[j][jhat];
a1258 1
      double rtmp;
a1274 1
  int itermax;
a1280 1
  int convergence, iter;
d1288 1
a1288 1
    for (int j = 0; j < naxis; j++) {
a1290 1
      double dd;
d1308 1
a1308 1
    for (int j = 0; j < naxis; j++) {
d1332 1
a1332 1
      for (int j = 0; j < naxis; j++) {
d1342 1
a1342 1
      for (int j = 0; j < naxis; j++) {
d1352 1
a1352 1
      for (int j = 0; j < naxis; j++) {
d1371 3
a1373 3
    double residual = 0.0;
    for (int j = 0; j < naxis; j++) {
      double dd = discrd[j] - dcrd0[j] ;
d1405 5
a1409 1
  int status = 0;
d1413 1
a1413 1
  struct wcserr **err = &(dis->err);
d1415 1
a1415 1
  int naxis = dis->naxis;
d1418 1
a1418 1
  for (int j = 0; j < naxis; j++) {
d1431 4
a1434 4
  double *pixinc = dis->tmpmem + naxis;
  double *pixend = pixinc + naxis;
  double *sumdis = pixend + naxis;
  double *ssqdis = sumdis + naxis;
d1437 2
a1438 2
  for (int j = 0; j < naxis; j++) {
    double pixspan = pixtrc[j] - (pixblc ? pixblc[j] : 1.0);
a1453 1
  double *pix0, *pix1;
d1462 1
a1462 1
  for (int j = 0; j < naxis; j++) {
d1468 1
a1468 1
  for (int j = 0; j < naxis; j++) {
d1472 2
a1473 2
  double sumtot = 0.0;
  double ssqtot = 0.0;
d1477 1
a1477 1
  int carry = 0;
d1487 4
a1490 4
    double dssq = 0.0;
    for (int j = 0; j < naxis; j++) {
      double dpix = pix1[j] - pix0[j];
      double dpx2 = dpix*dpix;
d1502 1
a1502 1
    double totdis = sqrt(dssq);
d1511 1
a1511 1
    for (int j = 0; j < naxis; j++) {
d1525 1
a1525 1
  for (int j = 0; j < naxis; j++) {
d1551 8
d1561 1
a1561 1
  struct wcserr **err = &(dis->err);
d1563 1
a1563 3
  int naxis = dis->naxis;

  char   id[32];
d1568 4
a1571 4
  int K = 0;
  int M = 0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
a1573 1
    char *fp;
d1597 5
a1601 5
  int Nhat = dis->Nhat[j];
  int nKparm = 2*(Nhat + 1);
  int nVar   = Nhat + K;
  int nTparm = 1 + nVar;
  int ndparm = K*nKparm + M*nTparm;
d1622 1
a1622 1
  int niparm = I_NPOLY + (2 + 2*M)*nVar;
d1625 1
a1625 1
  int lendp = ndparm + K;
d1637 2
a1638 2
  int    *iparm = dis->iparm[j];
  double *dparm = dis->dparm[j];
d1663 3
a1665 3
  double *dptr = dparm + (1 + Nhat);
  for (int k = 0; k < K; k++) {
    for (int jhat = 0; jhat <= Nhat; jhat++) {
d1673 1
a1673 1
  for (int m = 0; m < M; m++) {
a1678 1
  int i, k, m;
d1681 1
a1681 1
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d1685 1
a1685 1
    char *fp = strchr(keyp->field, '.') + 1;
a1701 1
      int offset;
a1713 1
      int jhat;
a1745 1
        int jhat;
d1753 1
a1753 1
        double power = dpkeyd(keyp);
d1766 1
a1766 1
        double power = dpkeyd(keyp);
d1795 1
a1795 1
  for (int ivar = 0; ivar < nVar; ivar++) {
d1801 1
a1801 1
  for (int ivar = 0; ivar < nVar; ivar++) {
d1804 1
a1804 1
      double power = dparm[i];
d1807 1
a1807 1
      int ipow = (int)power;
d1831 2
a1832 2
  int npow = 0;
  for (int ivar = 0; ivar < nVar; ivar++) {
d1870 6
d1877 1
a1877 1
  struct wcserr **err = &(dis->err);
a1878 1
  char id[32];
d1890 6
a1895 5
  int ncoeff[2] = {0, 0};
  int doaux     = 0;
  int doradial  = 0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d1898 1
a1898 1
    char *fp = strchr(keyp->field, '.') + 1;
a1901 1
      int idis;
a1913 1
      int k;
d1942 3
a1944 2
  int (*(distpd[2]))(DISP2X_ARGS) = {0x0, 0x0};
  for (int idis = 0; idis < 2; idis++) {
d2006 1
a2006 1
  int niparm = I_NTPD;
d2011 1
a2011 1
  int ndparm = (doaux?6:0) + ncoeff[0] + ncoeff[1];
d2041 1
a2041 1
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2044 1
a2044 1
    char *fp = strchr(keyp->field, '.') + 1;
a2048 1
      int k;
a2066 1
      int m;
d2073 1
a2073 1
      int idis = 3*(k-1) + m;
d2078 1
a2078 1
      int idis = (doaux?6:0);
a2082 1
      int k;
d2109 5
d2116 1
a2116 1
  struct wcserr **err = &(dis->err);
d2118 2
a2119 2
  int    *iparm = dis->iparm[j];
  double *dparm = dis->dparm[j];
d2123 1
a2123 1
  int Nhat = dis->Nhat[j];
d2127 1
a2127 1
  int K = iparm[I_K];
d2140 6
a2145 6
  int *iflgp = iparm + iparm[I_FLAGS];
  int *ipowp = iparm + iparm[I_IPOW];
  int degree = 0;
  for (int m = 0; m < iparm[I_M]; m++) {
    int deg = 0;
    for (int jhat = 0; jhat < Nhat; jhat++) {
d2180 1
a2180 1
  int ndparm = 0;
d2214 1
a2214 2
  int niparm = I_NTPD;
  int *tpd_iparm;
a2235 1
  double *tpd_dparm;
d2241 2
a2242 2
  double *dpolp = dparm + iparm[I_DPOLY];
  for (int m = 0; m < iparm[I_M]; m++) {
d2265 2
a2266 2
      int p[] = {0, 0};
      for (int jhat = 0; jhat < Nhat; jhat++) {
d2270 1
a2270 1
      int n = map[p[0]][p[1]];
d2296 6
d2304 1
a2304 1
  struct wcserr **err = &(dis->err);
a2306 1
  char id[32];
d2319 4
a2322 4
  int ndparm   = 0;
  int doradial = 0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2325 1
a2325 1
    char *fp = strchr(keyp->field, '.') + 1;
a2327 1
      int k;
d2390 1
a2390 1
  int niparm = I_NTPD;
d2417 1
a2417 1
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2420 1
a2420 1
    char *fp = strchr(keyp->field, '.') + 1;
a2423 1
      int k;
d2450 7
d2459 1
a2459 1
  struct wcserr **err = &(dis->err);
a2461 1
  char id[32];
d2474 4
a2477 3
  int degree[2] = {1, -1};
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2480 1
a2480 1
    char *fp = strchr(keyp->field, '.') + 1;
a2483 1
      int idis;
a2496 1
      int p, q;
d2498 1
a2498 1
      int deg = p + q;
d2518 3
a2520 2
  int (*(distpd[2]))(DISP2X_ARGS) = {0x0, 0x0}, ncoeff[2];
  for (int idis = 0; idis < 2; idis++) {
d2559 1
a2559 1
  int niparm = I_NTPD;
d2564 1
a2564 1
  int ndparm = ncoeff[0] + ncoeff[1];
d2588 1
a2588 1
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2591 1
a2591 1
    char *fp = strchr(keyp->field, '.') + 1;
a2594 1
      int idis;
a2600 1
      int p, q;
d2621 7
d2630 1
a2630 1
  struct wcserr **err = &(dis->err);
a2632 1
  char id[32];
d2646 1
a2646 1
  int ncoeff = 24;
d2654 1
a2654 1
  int niparm = I_NTPD;
d2659 1
a2659 1
  int ndparm = 6 + ncoeff;
a2683 1
  double A1, A2, A3, B1, B2, B3;
d2686 3
a2688 3
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
    char *fp = strchr(keyp->field, '.') + 1;
a2690 1
      int m;
d2715 2
a2716 2
  double X0 = (A2*B3 - A3*B1) / (A1*B1 - A2*B2);
  double Y0 = (A3*B2 - A1*B3) / (A1*B1 - A2*B2);
d2718 1
a2718 1
  double S = sqrt(fabs(A1*B1 - A2*B2));
d2725 1
a2725 1
  double *dparm = dis->dparm[j];
d2748 1
a2748 1
  int degree = 3;
d2750 1
a2750 1
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2753 1
a2753 1
    char *fp = strchr(keyp->field, '.') + 1;
d2757 1
a2757 2
      double coeff = dpkeyd(keyp);
      if (coeff == 0.0) continue;
a2759 1
      int m;
d2795 1
a2795 1
        degree = 5;
d2842 9
d2853 1
a2853 1
  struct wcserr **err = &(dis->err);
a2855 1
  char id[32];
d2869 6
a2874 8
  int degree = 1;
  int kind = 0;
  double xmin = 0.0;
  double xmax = 0.0;
  double ymin = 0.0;
  double ymax = 0.0;
  struct dpkey *keyp = dis->dp;
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d2877 1
a2877 1
    char *fp = strchr(keyp->field, '.') + 1;
a2885 1
        int m, n;
d2887 1
a2887 1
        int deg = m + n;
d2920 1
a2920 1
  int doaux = (kind == 1 || kind == 2);
d2923 1
a2923 1
  int ncoeff = 0;
d2967 1
a2967 1
  int niparm = I_NTPD;
d2972 1
a2972 1
  int *iparm = dis->iparm[j];
d2974 1
a2974 1
  int ndparm = 6 + ncoeff;
d2997 1
a2997 1
  double *dparm = dis->dparm[j];
d3002 2
a3003 2
    double x0 = (xmax + xmin)/2.0;
    double dx = (xmax - xmin)/2.0;
d3013 2
a3014 2
    double y0 = (ymax + ymin)/2.0;
    double dy = (ymax - ymin)/2.0;
d3030 1
a3030 1
  for (int idp = 0; idp < dis->ndp; idp++, keyp++) {
d3033 1
a3033 1
    char *fp = strchr(keyp->field, '.') + 1;
a3039 1
      int m, n;
d3044 1
a3044 1
        int idis = map[m][n];
d3050 1
a3050 1
        double coeff = dpkeyd(keyp);
a3051 1
        double coeffm[10], coeffn[10];
d3053 1
a3053 1
        for (int im = 0; im <= m; im++) {
d3056 1
a3056 1
          for (int in = 0; in <= n; in++) {
d3059 1
a3059 1
            int idis = map[im][in];
d3077 4
a3080 1
  int N = (m > n) ? m : n;
a3082 1
  double *coeff[3];
d3087 2
a3088 2
  for (int j = 0; j <= N; j++) {
    int j0 =  j%3;
d3098 2
a3099 2
      int j1 = (j-1)%3;
      int j2 = (j-2)%3;
d3103 2
a3104 2
      double d = (double)j;
      for (int k = 0; k < N; k++) {
d3135 5
d3144 1
a3144 1
  for (int jhat = 0; jhat < Nhat; jhat++) {
d3152 1
a3152 1
  double *aux = (double *)(dparm + iparm[I_DAUX]);
d3155 3
a3157 3
  for (int k = 0; k < iparm[I_K]; k++) {
    const double *cptr = dparm + k*iparm[I_NKPARM];
    const double *pptr = cptr + (1+Nhat);
d3160 1
a3160 1
    double auxp0  = *(pptr++);
d3162 1
a3162 1
    for (int jhat = 0; jhat < Nhat; jhat++) {
d3177 2
a3178 2
  const int *imaxpow = iparm + iparm[I_MAXPOW];
  double *dvarpow = (double *)(dparm + iparm[I_DVPOW]);
d3180 5
a3184 5
  const int *imaxp = imaxpow;
  double *dpowp = dvarpow;
  for (int jhat = 0; jhat < Nhat; jhat++, imaxp++) {
    double var = 1.0;
    for (int ip = 0; ip < *imaxp; ip++, dpowp++) {
d3190 3
a3192 3
  for (int k = 0; k < iparm[I_K]; k++, imaxp++) {
    double var = 1.0;
    for (int ip = 0; ip < *imaxp; ip++, dpowp++) {
d3200 5
a3204 5
  const int    *iflgp = iparm + iparm[I_FLAGS];
  const int    *ipowp = iparm + iparm[I_IPOW];
  const double *dpolp = dparm + iparm[I_DPOLY];
  for (int m = 0; m < iparm[I_M]; m++) {
    double term = *(dpolp++);
d3209 1
a3209 1
    for (int ivar = 0; ivar < iparm[I_NVAR]; ivar++) {
d3253 2
d3259 2
a3260 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3301 2
d3307 2
a3308 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3351 2
d3357 2
a3358 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3402 2
d3408 2
a3409 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3454 2
d3460 2
a3461 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3507 2
d3513 2
a3514 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3561 2
d3567 2
a3568 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3616 2
d3622 2
a3623 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
d3672 2
d3678 2
a3679 3
  double r, s;
  double u = rawcrd[0];
  double v = rawcrd[1];
@


7.6.1.3
log
@In disfree() and disset(), fixed possible problems freeing memory.
@
text
@d22 1
a22 1
  $Id: dis.c,v 7.6.1.2 2021/06/30 16:30:30 mcalabre Exp mcalabre $
d388 3
a390 13

    if (dis->iparm) {
      for (int j = 0; j < dis->i_naxis; j++) {
        if (dis->iparm[j]) free(dis->iparm[j]);
      }
      free(dis->iparm);
    }

    if (dis->dparm) {
      for (int j = 0; j < dis->i_naxis; j++) {
        if (dis->dparm[j]) free(dis->dparm[j]);
      }
      free(dis->dparm);
d392 2
a791 2
    dis->iparm[j] = 0x0;
    dis->dparm[j] = 0x0;
@


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: dis.c,v 7.4.1.1 2021/01/31 02:26:24 mcalabre Exp mcalabre $
d428 83
@


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


7.5.1.2
log
@Added new function dissize().
@
text
@d22 1
a22 1
  $Id: dis.c,v 7.5.1.1 2021/03/20 05:56:42 mcalabre Exp mcalabre $
a427 83
}

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

int dissize(const struct disprm *dis, int sizes[2])

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

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

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

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

  // disprm::dtype[].
  sizes[1] += naxis * sizeof(char [72]);

  // disprm::dp[].
  sizes[1] += dis->ndpmax * sizeof(struct dpkey);

  // disprm::maxdis[].
  sizes[1] += naxis * sizeof(double);

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

  // The remaining arrays are allocated by disset().
  if (dis->flag != DISSET) {
    return DISERR_SUCCESS;
  }

  // dis::docorr[].
  sizes[1] += naxis * sizeof(int *);

  // dis::Nhat[].
  sizes[1] += naxis * sizeof(int *);

  // dis::axmap[][].
  sizes[1] += naxis * sizeof(int *);
  sizes[1] += naxis*naxis * sizeof(int);

  // dis::offset[][].
  sizes[1] += naxis * sizeof(double *);
  sizes[1] += naxis*naxis * sizeof(double);

  // dis::scale[][].
  sizes[1] += naxis * sizeof(double *);
  sizes[1] += naxis*naxis * sizeof(double);

  // dis::iparm[][].
  sizes[1] += naxis * sizeof(int *);
  for (int j = 0; j < naxis; j++) {
    if (dis->iparm[j]) {
      sizes[1] += dis->iparm[j][I_NIPARM] * sizeof(int);
    }
  }

  // dis::dparm[][].
  sizes[1] += naxis * sizeof(double *);
  for (int j = 0; j < naxis; j++) {
    if (dis->dparm[j]) {
      sizes[1] += dis->dparm[j][I_NDPARM] * sizeof(double);
    }
  }

  // dis::disp2x[].
  sizes[1] += naxis * sizeof(int (*)(DISP2X_ARGS));

  // dis::disx2p[].
  sizes[1] += naxis * sizeof(int (*)(DISX2P_ARGS));

  // dis::tmpmem[].
  sizes[1] += 5*naxis * sizeof(double);

  return DISERR_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: dis.c,v 7.3.1.6 2021/01/29 09:29:47 mcalabre Exp mcalabre $
@


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


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

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

d22 1
a22 1
  $Id: dis.c,v 7.2.1.1 2020/03/09 07:34:50 mcalabre Exp mcalabre $
d41 1
a41 1
/* Maximum number of DPja or DQia keywords. */
d44 1
a44 1
/* Map status return value to message. */
d53 1
a53 1
/* Convenience macro for invoking wcserr_set(). */
d56 1
a56 1
/* Internal helper functions, not for general use. */
d78 5
a82 5
/* The first three iparm indices have meanings common to all distortion     */
/* functions.  They are used by disp2x(), disx2p(), disprt(), and dishdo(). */
#define I_DTYPE   0	/* Distortion type code.                            */
#define I_NIPARM  1	/* Full (allocated) length of iparm[].              */
#define I_NDPARM  2	/* No. of parameters in dparm[], excl. work space.  */
d84 1
a84 1
/*--------------------------------------------------------------------------*/
d88 1
a88 1
/*--------------------------------------------------------------------------*/
d105 1
a105 1
        /* Fill in the axis number from the value given. */
d109 1
a109 1
          /* Take care not to overwrite any alternate code. */
d128 1
a128 1
    /* The field name must either be given or preset. */
d143 1
a143 1
/*--------------------------------------------------------------------------*/
d155 1
a155 1
/*--------------------------------------------------------------------------*/
d167 1
a167 1
/*--------------------------------------------------------------------------*/
d175 1
a175 1
/*--------------------------------------------------------------------------*/
d184 1
a184 1
  /* Check inputs. */
d190 1
a190 1
  /* Initialize error message handling. */
d198 1
a198 1
  /* Initialize pointers. */
d217 1
a217 1
    /* Initialize memory management. */
d231 1
a231 1
  /* Allocate memory for arrays if required. */
d237 1
a237 1
    /* Was sufficient allocated previously? */
d241 1
a241 1
      /* No, free it. */
d247 1
a247 1
        /* In case the caller fiddled with it. */
d264 1
a264 1
        /* In case the caller fiddled with it. */
d287 1
a287 1
        /* In case the caller fiddled with it. */
d304 1
a304 1
  /* Set defaults. */
d326 1
a326 1
/*--------------------------------------------------------------------------*/
d361 1
a361 1
/*--------------------------------------------------------------------------*/
d371 1
a371 1
    /* Optionally allocated by disinit() for given parameters. */
d382 1
a382 1
    /* The remainder were allocated by disset(). */
d386 1
a386 1
    /* Recall that axmap, offset, and scale were allocated in bulk. */
d430 1
a430 1
/*--------------------------------------------------------------------------*/
d450 1
a450 1
  /* Parameters supplied. */
d480 1
a480 1
  /* Derived values. */
d559 1
a559 1
  /* Error handling. */
d565 1
a565 1
  /* Work arrays. */
d601 1
a601 1
  /* Memory management. */
d617 1
a617 1
/*--------------------------------------------------------------------------*/
d631 1
a631 1
/*--------------------------------------------------------------------------*/
d648 1
a648 1
        /* Implemented as TPD... */
d650 1
a650 1
          /* ... but isn't TPD. */
d654 1
a654 1
        /* Must be a Polynomial that can't be implemented as TPD. */
d664 1
a664 1
/*--------------------------------------------------------------------------*/
d682 1
a682 1
  /* Do basic checks. */
d697 1
a697 1
    /* Is it prior or sequent? */
d714 2
a715 2
    /* A Clayton's distortion.  Avert compiler warnings about possible use of
       uninitialized variables. */
d720 1
a720 1
  /* Free memory allocated separately for each axis. */
d726 2
a727 2
  /* Allocate or reallocate memory, if necessary, for derived parameter and
     work arrays sized according to the number of axes. */
d733 1
a733 1
      /* Noting that axmap, offset, and scale are allocated in bulk. */
d760 1
a760 1
    /* Allocate axmap[][] in bulk and then carve it up. */
d775 1
a775 1
    /* Allocate offset[][] in bulk and then carve it up. */
d790 1
a790 1
    /* Allocate scale[][] in bulk and then carve it up. */
d833 1
a833 1
  /* Start with a clean slate. */
d850 1
a850 1
  /* polyset() etc. must look after iparm[][] and dparm[][]. */
d860 1
a860 1
  /* Handle DPja or DQia keywords common to all distortions. */
d863 1
a863 1
    /* Check that they're all one kind or the other. */
d882 1
a882 1
    /* Convert to 0-relative axis number. */
d908 1
a908 1
      /* N.B. axis numbers in the map are 0-relative. */
d921 1
a921 1
  /* Set defaults and do sanity checks on axmap[][].  */
d924 1
a924 1
      /* No distortion on this axis, check that there are no parameters. */
d937 1
a937 1
    /* N.B. NAXES (Nhat) has no default value. */
d944 1
a944 1
    /* Set defaults for axmap[][]. */
d952 1
a952 1
    /* Sanity check on the length of the axis map. */
d964 1
a964 1
    /* Check uniqueness of entries in the axis map. */
d977 1
a977 1
  /* Identify the distortion functions. */
d981 1
a981 1
      /* No distortion on this axis. */
d990 1
a990 1
    /* Invoke the specific setup functions for each distortion. */
d992 1
a992 1
      /* Template Polynomial Distortion. */
d994 1
a994 1
        /* (Preserve the error message set by tpdset().) */
d999 1
a999 1
      /* TPV "projection". */
d1001 1
a1001 1
        /* (Preserve the error message set by tpvset().) */
d1006 1
a1006 1
      /* Simple Imaging Polynomial (SIP). */
d1008 1
a1008 1
        /* (Preserve the error message set by sipset().) */
d1013 1
a1013 1
      /* Digitized Sky Survey (DSS). */
d1015 1
a1015 1
        /* (Preserve the error message set by dssset().) */
d1020 1
a1020 1
      /* WAT (TNX or ZPX "projections"). */
d1022 1
a1022 1
        /* (Preserve the error message set by watset().) */
d1028 1
a1028 1
      /* General polynomial distortion. */
d1030 1
a1030 1
        /* (Preserve the error message set by polyset().) */
d1048 1
a1048 1
/*--------------------------------------------------------------------------*/
d1063 1
a1063 1
  /* Initialize. */
d1074 1
a1074 1
  /* Invoke the distortion functions for each axis. */
d1093 1
a1093 1
        /* Distortion function computes a correction to be applied. */
d1096 1
a1096 1
        /* Distortion function computes corrected coordinates. */
d1108 3
a1110 3
/*--------------------------------------------------------------------------*/
/* This function is intended for debugging purposes only.                   */
/* No documentation or prototype is provided in dis.h.                      */
d1124 1
a1124 1
/*--------------------------------------------------------------------------*/
d1142 1
a1142 1
  /* Initialize. */
d1148 1
a1148 1
  /* Carve up working memory, noting that disp2x() gets to it first. */
d1155 6
a1160 6
  /* Zeroth approximation.  The assumption here and below is that the     */
  /* distortion is small so that, to first order in the neighbourhood of  */
  /* the solution, discrd[j] ~= a + b*rawcrd[j], i.e. independent of      */
  /* rawcrd[i], where i != j.  This is effectively equivalent to assuming */
  /* that the distortion functions are separable to first order.          */
  /* Furthermore, a is assumed to be small, and b close to unity.         */
d1163 1
a1163 1
  /* If available, use disprm::disx2p to improve the zeroth approximation. */
d1182 1
a1182 1
        /* Inverse distortion function computes a correction to be applied. */
d1185 1
a1185 1
        /* Inverse distortion function computes corrected coordinates. */
d1191 1
a1191 1
  /* Quick return debugging hook, assumes inverse functions were defined. */
d1197 1
a1197 1
  /* Iteratively invert the (well-behaved!) distortion function. */
d1203 1
a1203 1
    /* Check for convergence. */
d1211 2
a1212 2
        /* TOL may be below the precision achievable from floating point */
        /* subtraction, so switch to a fractional tolerance.             */
d1217 1
a1217 1
        /* No convergence yet on this axis. */
d1224 1
a1224 1
    /* Determine a suitable test point for computing the gradient. */
d1226 1
a1226 1
      /* Constrain the displacement. */
d1244 5
a1248 5
      /* With the assumption of small distortions (as above), the gradient */
      /* of discrd[j] should be dominated by the partial derivative with   */
      /* respect to rawcrd[j], and we can neglect partials with respect    */
      /* to rawcrd[i], where i != j.  Thus only one test point is needed,  */
      /* not one for each axis.                                            */
d1253 1
a1253 1
      /* Compute discrd[] at the test point. */
d1258 1
a1258 1
      /* Compute the next approximation. */
d1265 2
a1266 2
      /* Convergence should not take more than seven or so iterations.  As */
      /* it is slow, try computing the gradient in full.                   */
d1272 1
a1272 1
        /* Compute discrd[] at the test point. */
d1277 1
a1277 1
        /* Compute the next approximation. */
d1304 1
a1304 1
/*--------------------------------------------------------------------------*/
d1328 1
a1328 1
  /* Initialize. */
d1344 1
a1344 1
  /* Quick return if no distortions. */
d1347 1
a1347 1
  /* Carve up working memory, noting that disp2x() gets to it first. */
d1353 1
a1353 1
  /* Work out increments on each axis. */
d1370 1
a1370 1
  /* Get some more memory for coordinate vectors. */
d1378 1
a1378 1
  /* Set up the array of pixel coordinates. */
d1384 1
a1384 1
  /* Initialize accumulators. */
d1393 1
a1393 1
  /* Loop over N dimensions. */
d1397 1
a1397 1
      /* (Preserve the error message set by disp2x().) */
d1401 1
a1401 1
    /* Accumulate statistics. */
d1427 1
a1427 1
    /* Next pixel. */
d1441 1
a1441 1
  /* Compute the means and RMSs. */
d1461 1
a1461 1
/*--------------------------------------------------------------------------*/
d1476 1
a1476 1
  /* Initialize. */
d1484 1
a1484 1
  /* Find the number of auxiliary variables and terms. */
d1520 16
a1535 16
/* These iparm indices are specific to Polynomial.                          */
#define I_NIDX    3	/* No. of indexes in iparm[].                       */
#define I_LENDP   4	/* Full (allocated) length of dparm[].              */
#define I_K       5	/* No. of auxiliary variables.                      */
#define I_M       6	/* No. of terms in the polynomial.                  */
#define I_NKPARM  7	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  8	/* No. of parameters used to define each term.      */
#define I_NVAR    9	/* No. of independent + auxiliary variables.        */
#define I_MNVAR  10	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  11	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   12	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  13	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 14	/* iparm offset for max powers.                     */
#define I_DPOFF  15	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  16	/* iparm offset for flags.                          */
#define I_IPOW   17	/* iparm offset for integral powers.                */
d1538 1
a1538 1
  /* Add extra for handling integer exponents.  See "Optimization" below. */
d1541 1
a1541 1
  /* Add extra memory for temporaries. */
d1544 1
a1544 1
  /* Allocate memory for the indexes and parameter array. */
d1553 1
a1553 1
  /* These help a bit to stop the code from turning into hieroglyphics. */
d1558 1
a1558 1
  /* Record the indexing parameters.  The first three are more widely used. */
d1579 1
a1579 1
  /* Set default values of POWER for the auxiliary variables. */
d1588 1
a1588 1
  /* Set default values of COEFF for the independent variables. */
d1595 1
a1595 1
  /* Extract parameter values from DPja or DQia. */
d1599 1
a1599 1
    /* N.B. keyp->j is 1-relative, but j is 0-relative. */
d1605 1
a1605 1
      /* N.B. k here is 1-relative. */
d1633 1
a1633 1
        /* N.B. jhat == 0 is ok. */
d1642 1
a1642 1
      /* N.B. m here is 1-relative. */
d1661 1
a1661 1
        /* N.B. jhat here is 1-relative. */
d1674 1
a1674 1
        /* N.B. k here is 1-relative. */
d1704 8
a1711 8
  /* Optimization: when the power is integral, it is faster to multiply     */
  /* ------------  repeatedly than call pow().  iparm[] is constructed as   */
  /*               follows:                                                 */
  /*  I_NPOLY indexing parameters, as above,                                */
  /*     nVar elements record the largest integral power for each variable, */
  /*     nVar elements record offsets into dparm for each variable,         */
  /*   M*nVar flags to signal whether the power is integral,                */
  /*   M*nVar integral powers.                                              */
d1713 1
a1713 1
    /* Want at least the first degree power for all variables. */
d1723 1
a1723 1
      /* Is it integral?  (Positive, negative, or zero.) */
d1726 1
a1726 1
        /* Signal that the power is integral. */
d1734 1
a1734 1
        /* The integral power itself. */
d1739 1
a1739 1
      /* Record the largest integral power for each variable. */
d1747 1
a1747 1
  /* How many of all powers of each variable will there be? */
d1750 1
a1750 1
    /* Offset into dparm. */
d1758 1
a1758 1
  /* Expand dparm to store the extra powers. */
d1767 1
a1767 1
  /* No specialist de-distortions. */
d1771 2
a1772 2
  /* Translate Polynomial to TPD if possible, it's much faster.  */
  /* However don't do it if the name was given as "Polynomial*". */
d1780 1
a1780 1
/*--------------------------------------------------------------------------*/
d1799 1
a1799 1
  /* TPD distortion. */
d1806 1
a1806 1
  /* Find the number of parameters. */
d1823 1
a1823 1
        /* TPD may provide a polynomial approximation for the inverse. */
d1835 1
a1835 1
        /* Any radial terms? */
d1846 1
a1846 1
      /* Flag usage of auxiliary variables. */
d1864 1
a1864 1
        /* No inverse polynomial. */
d1868 1
a1868 1
      /* First degree. */
d1872 1
a1872 1
      /* Second degree. */
d1876 1
a1876 1
      /* Third degree. */
d1880 1
a1880 1
      /* Fourth degree. */
d1884 1
a1884 1
      /* Fifth degree. */
d1888 1
a1888 1
      /* Sixth degree. */
d1892 1
a1892 1
      /* Seventh degree. */
d1896 1
a1896 1
      /* Eighth degree. */
d1900 1
a1900 1
      /* Ninth degree. */
d1909 2
a1910 2
  /* disx2p() only uses the inverse TPD, if present, to provide a better */
  /* zeroth approximation. */
d1915 5
a1919 5
/* These iparm indices are specific to TPD.                      */
#define I_TPDNCO  3	/* No. of TPD coefficients, forward...   */
#define I_TPDINV  4	/* ...and inverse.                       */
#define I_TPDAUX  5	/* True if auxiliary variables are used. */
#define I_TPDRAD  6	/* True if the radial variable is used.  */
d1922 1
a1922 1
  /* Record indexing parameters. */
d1930 1
a1930 1
  /* The first three are more widely used. */
d1935 1
a1935 1
  /* Number of TPD coefficients. */
d1939 1
a1939 1
  /* Flag for presence of auxiliary variables. */
d1942 1
a1942 1
  /* Flag for presence of radial terms. */
d1946 1
a1946 1
  /* Allocate memory for the polynomial coefficients and fill it. */
d1951 1
a1951 1
  /* Set default auxiliary coefficients. */
d1964 1
a1964 1
      /* Auxiliary variables. */
d2008 1
a2008 1
/*--------------------------------------------------------------------------*/
d2031 1
a2031 1
  /* Initialize. */
d2039 1
a2039 1
  /* Check the number of independent variables, no more than two. */
d2043 1
a2043 1
  /* Check auxiliaries: only one is allowed... */
d2047 1
a2047 1
    /* ...and it must be radial. */
d2056 1
a2056 1
  /* Check powers... */
d2063 1
a2063 1
      /* ...they must be positive integral. */
d2071 1
a2071 1
    /* The polynomial degree can't be greater than 9. */
d2075 1
a2075 1
      /* Likewise for the radial variable. */
d2081 1
a2081 1
        /* Can't mix the radial and other terms. */
d2084 1
a2084 1
        /* Can't have even powers of the radial variable. */
d2096 1
a2096 1
  /* OK, it ticks all the boxes.  Now translate it. */
d2127 1
a2127 1
  /* No specialist de-distortions. */
d2130 1
a2130 1
  /* Record indexing parameters. */
d2136 1
a2136 1
  /* The first three are more widely used. */
d2141 1
a2141 1
  /* Number of TPD coefficients. */
d2145 1
a2145 1
  /* No auxiliary variables yet. */
d2148 1
a2148 1
  /* Flag for presence of radial terms. */
d2152 1
a2152 1
  /* Allocate memory for the polynomial coefficients and fill it. */
d2161 1
a2161 1
      /* The radial variable. */
d2181 1
a2181 1
      /* The independent variables. */
d2197 1
a2197 1
  /* Switch from Polynomial to TPD. */
d2206 1
a2206 1
/*--------------------------------------------------------------------------*/
d2219 1
a2219 1
  /* Initialize. */
d2223 1
a2223 1
  /* TPV "projection". */
d2226 2
a2227 1
  /* TPV computes corrected coordinates. */
d2235 1
a2235 1
  /* Find the number of parameters. */
d2249 1
a2249 1
        /* Any radial terms? */
d2268 1
a2268 1
  /* TPD is going to do the dirty work. */
d2270 1
a2270 1
    /* First degree. */
d2274 1
a2274 1
    /* Second degree. */
d2278 1
a2278 1
    /* Third degree. */
d2282 1
a2282 1
    /* Fourth degree. */
d2286 1
a2286 1
    /* Fifth degree. */
d2290 1
a2290 1
    /* Sixth degree. */
d2294 1
a2294 1
    /* Seventh degree. */
d2298 1
a2298 1
    /* Could go to ninth degree, but that wouldn't be legit. */
d2303 1
a2303 1
  /* No specialist de-distortions. */
d2306 1
a2306 1
  /* Record indexing parameters. */
d2312 1
a2312 1
  /* The first three are more widely used. */
d2317 1
a2317 1
  /* Number of TPD coefficients. */
d2321 1
a2321 1
  /* TPV never needs auxiliary variables. */
d2324 1
a2324 1
  /* Flag for presence of radial terms. */
d2328 1
a2328 1
  /* Allocate memory for the polynomial coefficients and fill it. */
d2339 1
a2339 1
    /* One-to-one correspondence between TPV and TPD coefficients. */
d2349 1
a2349 1
/*--------------------------------------------------------------------------*/
d2374 1
a2374 1
  /* Initialize. */
d2378 1
a2378 1
  /* Simple Imaging Polynomial. */
d2382 1
a2382 1
  /* SIP computes an additive correction. */
d2390 1
a2390 1
  /* Find the polynomial degree, at least 1 for the forward function. */
d2405 1
a2405 1
        /* SIP uses a polynomial approximation for the inverse. */
d2434 1
a2434 1
  /* TPD is going to do the dirty work. */
d2469 2
a2470 2
  /* SIP uses a polynomial approximation to the inverse.  It's not very    */
  /* accurate but may provide disx2p() with a better zeroth approximation. */
d2475 1
a2475 1
  /* Record indexing parameters. */
d2483 1
a2483 1
  /* The first three are more widely used. */
d2488 1
a2488 1
  /* Number of TPD coefficients. */
d2492 1
a2492 1
  /* SIP never needs auxiliary variables. */
d2495 1
a2495 1
  /* SIP never needs the radial terms. */
d2499 1
a2499 1
  /* Allocate memory for the polynomial coefficients and fill it. */
d2520 1
a2520 1
      /* Map to TPD coefficient number. */
d2531 1
a2531 1
/*--------------------------------------------------------------------------*/
d2545 1
a2545 1
  /* Initialize. */
d2549 1
a2549 1
  /* Digitized Sky Survey. */
d2553 2
a2554 1
  /* DSS computes corrected coordinates. */
d2562 1
a2562 1
  /* Safe to assume the polynomial degree is 5 (or less). */
d2566 1
a2566 1
  /* No specialist de-distortions. */
d2570 1
a2570 1
  /* Record indexing parameters. */
d2578 1
a2578 1
  /* The first three are more widely used. */
d2583 1
a2583 1
  /* Number of TPD coefficients. */
d2587 1
a2587 1
  /* DSS always needs auxiliary variables. */
d2590 1
a2590 1
  /* DSS never needs the radial terms. */
d2594 1
a2594 1
  /* Allocate memory for the polynomial coefficients and fill it. */
d2599 2
a2600 2
  /* This translation follows WCS Paper IV, Sect. 5.2 using the same */
  /* variable names.  Find A1, A2, A3, B1, B2, and B3.               */
d2641 1
a2641 1
  /* Coefficients for the auxiliary variables. */
d2651 1
a2651 1
    /* Change the sign of S for scaling the A coefficients. */
d2663 1
a2663 1
  /* Translate DSS coefficients to TPD. */
d2673 1
a2673 1
      /* Skip zero coefficients. */
d2679 1
a2679 1
      /* Apply the coefficient scale factor. */
d2727 2
a2728 2
  /* The DSS polynomial doesn't have 4th degree terms, and the 5th degree
     coefficient is often zero. */
d2737 1
a2737 1
/*--------------------------------------------------------------------------*/
d2768 1
a2768 1
  /* Initialize. */
d2772 1
a2772 1
  /* WAT (TNX or ZPX) Polynomial. */
d2776 2
a2777 1
  /* WAT computes an additive correction. */
d2785 1
a2785 1
  /* Find the polynomial degree (at least 1), kind, and domain. */
d2839 1
a2839 1
  /* TPD is going to do the dirty work. */
d2842 1
a2842 1
    /* First degree. */
d2846 1
a2846 1
    /* Second degree. */
d2850 1
a2850 1
    /* Third degree. */
d2854 1
a2854 1
    /* Fourth degree. */
d2858 1
a2858 1
    /* Fifth degree. */
d2862 1
a2862 1
    /* Sixth degree. */
d2866 1
a2866 1
    /* Seventh degree. */
d2870 1
a2870 1
    /* Eighth degree. */
d2874 1
a2874 1
    /* Ninth degree. */
d2879 1
a2879 1
  /* No specialist de-distortions. */
d2883 1
a2883 1
  /* Record indexing parameters. */
d2893 1
a2893 1
  /* The first three are more widely used. */
d2898 1
a2898 1
  /* Number of TPD coefficients. */
d2902 1
a2902 1
  /* The Chebyshev and Legendre polynomials use auxiliary variables. */
d2905 1
a2905 1
  /* WAT never needs the radial terms. */
d2909 1
a2909 1
  /* Allocate memory for the polynomial coefficients and fill it. */
d2917 1
a2917 1
  /* Coefficients for the auxiliary variables. */
d2945 1
a2945 1
  /* Unpack the polynomial coefficients. */
d2960 1
a2960 1
        /* Monomial coefficient, maps simply to TPD coefficient number. */
d2965 2
a2966 2
        /* Coefficient of the product of two Chebyshev or two Legendre */
        /* polynomials.  Find the corresponding monomial coefficients. */
d2987 3
a2989 3
/*--------------------------------------------------------------------------*/
/* Compute the coefficients of Chebyshev or Legendre polynomials of degree  */
/* m and n.                                                                 */
d2999 1
a2999 1
  /* Allocate work arrays. */
d3014 1
a3014 1
      /* Cyclic buffer indices. */
d3041 1
a3041 1
/*--------------------------------------------------------------------------*/
d3057 1
a3057 1
  /* Avert nuisance compiler warnings about unused parameters. */
d3060 1
a3060 1
  /* Check for zeroes. */
d3068 1
a3068 1
  /* Working memory for auxiliaries &c. was allocated at the end of p[]. */
d3071 1
a3071 1
  /* Compute the auxiliary variables. */
d3085 1
a3085 1
    /* Check for zeroes. */
d3093 1
a3093 1
  /* Compute all required integral powers of the variables. */
d3115 1
a3115 1
  /* Loop for each term of the polynomial. */
d3123 1
a3123 1
    /* Loop over all variables. */
d3128 1
a3128 1
        /* Nothing (zero power). */
d3131 1
a3131 1
        /* Integral power. */
d3133 1
a3133 1
          /* Negative. */
d3136 1
a3136 1
          /* Positive. */
d3141 1
a3141 1
        /* Fractional power. */
d3159 1
a3159 1
/*--------------------------------------------------------------------------*/
d3179 1
a3179 1
  /* Auxiliary variables? */
d3189 1
a3189 1
  /* First degree. */
d3196 1
a3196 1
  /* Radial terms? */
d3207 1
a3207 1
/*--------------------------------------------------------------------------*/
d3227 1
a3227 1
  /* Auxiliary variables? */
d3237 1
a3237 1
  /* Second degree. */
d3246 1
a3246 1
  /* Radial terms? */
d3257 1
a3257 1
/*--------------------------------------------------------------------------*/
d3277 1
a3277 1
  /* Auxiliary variables? */
d3287 1
a3287 1
  /* Third degree. */
d3297 1
a3297 1
  /* Radial terms? */
d3308 1
a3308 1
/*--------------------------------------------------------------------------*/
d3328 1
a3328 1
  /* Auxiliary variables? */
d3338 1
a3338 1
  /* Fourth degree. */
d3349 1
a3349 1
  /* Radial terms? */
d3360 1
a3360 1
/*--------------------------------------------------------------------------*/
d3380 1
a3380 1
  /* Auxiliary variables? */
d3390 1
a3390 1
  /* Fifth degree. */
d3402 1
a3402 1
  /* Radial terms? */
d3413 1
a3413 1
/*--------------------------------------------------------------------------*/
d3433 1
a3433 1
  /* Auxiliary variables? */
d3443 1
a3443 1
  /* Sixth degree. */
d3456 1
a3456 1
  /* Radial terms? */
d3467 1
a3467 1
/*--------------------------------------------------------------------------*/
d3487 1
a3487 1
  /* Auxiliary variables? */
d3497 1
a3497 1
  /* Seventh degree. */
d3511 1
a3511 1
  /* Radial terms? */
d3522 1
a3522 1
/*--------------------------------------------------------------------------*/
d3542 1
a3542 1
  /* Auxiliary variables? */
d3552 1
a3552 1
  /* Eighth degree. */
d3567 1
a3567 1
  /* Radial terms? */
d3578 1
a3578 1
/*--------------------------------------------------------------------------*/
d3598 1
a3598 1
  /* Auxiliary variables? */
d3608 1
a3608 1
  /* Ninth degree. */
d3624 1
a3624 1
  /* Radial terms? */
@


7.3.1.1
log
@WCSLIB 7.3 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 7.3.1.1 2020/06/03 03:38:10 mcalabre Exp mcalabre $
d44 1
a44 1
// Maximum number of DPja or DQia keywords.
d47 1
a47 1
// Map status return value to message.
d56 1
a56 1
// Convenience macro for invoking wcserr_set().
d59 1
a59 1
// Internal helper functions, not for general use.
d81 5
a85 5
// The first three iparm indices have meanings common to all distortion
// functions.  They are used by disp2x(), disx2p(), disprt(), and dishdo().
#define I_DTYPE   0	// Distortion type code.
#define I_NIPARM  1	// Full (allocated) length of iparm[].
#define I_NDPARM  2	// No. of parameters in dparm[], excl. work space.
d87 1
a87 1
//----------------------------------------------------------------------------
d91 1
a91 1
//----------------------------------------------------------------------------
d108 1
a108 1
        // Fill in the axis number from the value given.
d112 1
a112 1
          // Take care not to overwrite any alternate code.
d131 1
a131 1
    // The field name must either be given or preset.
d146 1
a146 1
//----------------------------------------------------------------------------
d158 1
a158 1
//----------------------------------------------------------------------------
d170 1
a170 1
//----------------------------------------------------------------------------
d178 1
a178 1
//----------------------------------------------------------------------------
d187 1
a187 1
  // Check inputs.
d193 1
a193 1
  // Initialize error message handling.
d201 1
a201 1
  // Initialize pointers.
d220 1
a220 1
    // Initialize memory management.
d234 1
a234 1
  // Allocate memory for arrays if required.
d240 1
a240 1
    // Was sufficient allocated previously?
d244 1
a244 1
      // No, free it.
d250 1
a250 1
        // In case the caller fiddled with it.
d267 1
a267 1
        // In case the caller fiddled with it.
d290 1
a290 1
        // In case the caller fiddled with it.
d307 1
a307 1
  // Set defaults.
d329 1
a329 1
//----------------------------------------------------------------------------
d364 1
a364 1
//----------------------------------------------------------------------------
d374 1
a374 1
    // Optionally allocated by disinit() for given parameters.
d385 1
a385 1
    // The remainder were allocated by disset().
d389 1
a389 1
    // Recall that axmap, offset, and scale were allocated in bulk.
d433 1
a433 1
//----------------------------------------------------------------------------
d453 1
a453 1
  // Parameters supplied.
d483 1
a483 1
  // Derived values.
d562 1
a562 1
  // Error handling.
d568 1
a568 1
  // Work arrays.
d604 1
a604 1
  // Memory management.
d620 1
a620 1
//----------------------------------------------------------------------------
d634 1
a634 1
//----------------------------------------------------------------------------
d651 1
a651 1
        // Implemented as TPD...
d653 1
a653 1
          // ... but isn't TPD.
d657 1
a657 1
        // Must be a Polynomial that can't be implemented as TPD.
d667 1
a667 1
//----------------------------------------------------------------------------
d685 1
a685 1
  // Do basic checks.
d700 1
a700 1
    // Is it prior or sequent?
d717 2
a718 2
    // A Clayton's distortion.  Avert compiler warnings about possible use of
    // uninitialized variables.
d723 1
a723 1
  // Free memory allocated separately for each axis.
d729 2
a730 2
  // Allocate or reallocate memory, if necessary, for derived parameter and
  // work arrays sized according to the number of axes.
d736 1
a736 1
      // Noting that axmap, offset, and scale are allocated in bulk.
d763 1
a763 1
    // Allocate axmap[][] in bulk and then carve it up.
d778 1
a778 1
    // Allocate offset[][] in bulk and then carve it up.
d793 1
a793 1
    // Allocate scale[][] in bulk and then carve it up.
d836 1
a836 1
  // Start with a clean slate.
d853 1
a853 1
  // polyset() etc. must look after iparm[][] and dparm[][].
d863 1
a863 1
  // Handle DPja or DQia keywords common to all distortions.
d866 1
a866 1
    // Check that they're all one kind or the other.
d885 1
a885 1
    // Convert to 0-relative axis number.
d911 1
a911 1
      // N.B. axis numbers in the map are 0-relative.
d924 1
a924 1
  // Set defaults and do sanity checks on axmap[][].
d927 1
a927 1
      // No distortion on this axis, check that there are no parameters.
d940 1
a940 1
    // N.B. NAXES (Nhat) has no default value.
d947 1
a947 1
    // Set defaults for axmap[][].
d955 1
a955 1
    // Sanity check on the length of the axis map.
d967 1
a967 1
    // Check uniqueness of entries in the axis map.
d980 1
a980 1
  // Identify the distortion functions.
d984 1
a984 1
      // No distortion on this axis.
d993 1
a993 1
    // Invoke the specific setup functions for each distortion.
d995 1
a995 1
      // Template Polynomial Distortion.
d997 1
a997 1
        // (Preserve the error message set by tpdset().)
d1002 1
a1002 1
      // TPV "projection".
d1004 1
a1004 1
        // (Preserve the error message set by tpvset().)
d1009 1
a1009 1
      // Simple Imaging Polynomial (SIP).
d1011 1
a1011 1
        // (Preserve the error message set by sipset().)
d1016 1
a1016 1
      // Digitized Sky Survey (DSS).
d1018 1
a1018 1
        // (Preserve the error message set by dssset().)
d1023 1
a1023 1
      // WAT (TNX or ZPX "projections").
d1025 1
a1025 1
        // (Preserve the error message set by watset().)
d1031 1
a1031 1
      // General polynomial distortion.
d1033 1
a1033 1
        // (Preserve the error message set by polyset().)
d1051 1
a1051 1
//----------------------------------------------------------------------------
d1066 1
a1066 1
  // Initialize.
d1077 1
a1077 1
  // Invoke the distortion functions for each axis.
d1096 1
a1096 1
        // Distortion function computes a correction to be applied.
d1099 1
a1099 1
        // Distortion function computes corrected coordinates.
d1111 3
a1113 3
//----------------------------------------------------------------------------
// This function is intended for debugging purposes only.
// No documentation or prototype is provided in dis.h.
d1127 1
a1127 1
//----------------------------------------------------------------------------
d1145 1
a1145 1
  // Initialize.
d1151 1
a1151 1
  // Carve up working memory, noting that disp2x() gets to it first.
d1158 6
a1163 6
  // Zeroth approximation.  The assumption here and below is that the
  // distortion is small so that, to first order in the neighbourhood of
  // the solution, discrd[j] ~= a + b*rawcrd[j], i.e. independent of
  // rawcrd[i], where i != j.  This is effectively equivalent to assuming
  // that the distortion functions are separable to first order.
  // Furthermore, a is assumed to be small, and b close to unity.
d1166 1
a1166 1
  // If available, use disprm::disx2p to improve the zeroth approximation.
d1185 1
a1185 1
        // Inverse distortion function computes a correction to be applied.
d1188 1
a1188 1
        // Inverse distortion function computes corrected coordinates.
d1194 1
a1194 1
  // Quick return debugging hook, assumes inverse functions were defined.
d1200 1
a1200 1
  // Iteratively invert the (well-behaved!) distortion function.
d1206 1
a1206 1
    // Check for convergence.
d1214 2
a1215 2
        // TOL may be below the precision achievable from floating point
        // subtraction, so switch to a fractional tolerance.
d1220 1
a1220 1
        // No convergence yet on this axis.
d1227 1
a1227 1
    // Determine a suitable test point for computing the gradient.
d1229 1
a1229 1
      // Constrain the displacement.
d1247 5
a1251 5
      // With the assumption of small distortions (as above), the gradient
      // of discrd[j] should be dominated by the partial derivative with
      // respect to rawcrd[j], and we can neglect partials with respect
      // to rawcrd[i], where i != j.  Thus only one test point is needed,
      // not one for each axis.
d1256 1
a1256 1
      // Compute discrd[] at the test point.
d1261 1
a1261 1
      // Compute the next approximation.
d1268 2
a1269 2
      // Convergence should not take more than seven or so iterations.  As
      // it is slow, try computing the gradient in full.
d1275 1
a1275 1
        // Compute discrd[] at the test point.
d1280 1
a1280 1
        // Compute the next approximation.
d1307 1
a1307 1
//----------------------------------------------------------------------------
d1331 1
a1331 1
  // Initialize.
d1347 1
a1347 1
  // Quick return if no distortions.
d1350 1
a1350 1
  // Carve up working memory, noting that disp2x() gets to it first.
d1356 1
a1356 1
  // Work out increments on each axis.
d1373 1
a1373 1
  // Get some more memory for coordinate vectors.
d1381 1
a1381 1
  // Set up the array of pixel coordinates.
d1387 1
a1387 1
  // Initialize accumulators.
d1396 1
a1396 1
  // Loop over N dimensions.
d1400 1
a1400 1
      // (Preserve the error message set by disp2x().)
d1404 1
a1404 1
    // Accumulate statistics.
d1430 1
a1430 1
    // Next pixel.
d1444 1
a1444 1
  // Compute the means and RMSs.
d1464 1
a1464 1
//----------------------------------------------------------------------------
d1479 1
a1479 1
  // Initialize.
d1487 1
a1487 1
  // Find the number of auxiliary variables and terms.
d1523 16
a1538 16
// These iparm indices are specific to Polynomial.
#define I_NIDX    3	// No. of indexes in iparm[].
#define I_LENDP   4	// Full (allocated) length of dparm[].
#define I_K       5	// No. of auxiliary variables.
#define I_M       6	// No. of terms in the polynomial.
#define I_NKPARM  7	// No. of parameters used to define each auxiliary.
#define I_NTPARM  8	// No. of parameters used to define each term.
#define I_NVAR    9	// No. of independent + auxiliary variables.
#define I_MNVAR  10	// No. of powers (exponents) in the polynomial.
#define I_DPOLY  11	// dparm offset for polynomial coefficients.
#define I_DAUX   12	// dparm offset for auxiliary coefficients.
#define I_DVPOW  13	// dparm offset for integral powers of variables.
#define I_MAXPOW 14	// iparm offset for max powers.
#define I_DPOFF  15	// iparm offset for dparm offsets.
#define I_FLAGS  16	// iparm offset for flags.
#define I_IPOW   17	// iparm offset for integral powers.
d1541 1
a1541 1
  // Add extra for handling integer exponents.  See "Optimization" below.
d1544 1
a1544 1
  // Add extra memory for temporaries.
d1547 1
a1547 1
  // Allocate memory for the indexes and parameter array.
d1556 1
a1556 1
  // These help a bit to stop the code from turning into hieroglyphics.
d1561 1
a1561 1
  // Record the indexing parameters.  The first three are more widely used.
d1582 1
a1582 1
  // Set default values of POWER for the auxiliary variables.
d1591 1
a1591 1
  // Set default values of COEFF for the independent variables.
d1598 1
a1598 1
  // Extract parameter values from DPja or DQia.
d1602 1
a1602 1
    // N.B. keyp->j is 1-relative, but j is 0-relative.
d1608 1
a1608 1
      // N.B. k here is 1-relative.
d1636 1
a1636 1
        // N.B. jhat == 0 is ok.
d1645 1
a1645 1
      // N.B. m here is 1-relative.
d1664 1
a1664 1
        // N.B. jhat here is 1-relative.
d1677 1
a1677 1
        // N.B. k here is 1-relative.
d1707 8
a1714 8
  // Optimization: when the power is integral, it is faster to multiply
  // ------------  repeatedly than call pow().  iparm[] is constructed as
  //               follows:
  //  I_NPOLY indexing parameters, as above,
  //     nVar elements record the largest integral power for each variable,
  //     nVar elements record offsets into dparm for each variable,
  //   M*nVar flags to signal whether the power is integral,
  //   M*nVar integral powers.
d1716 1
a1716 1
    // Want at least the first degree power for all variables.
d1726 1
a1726 1
      // Is it integral?  (Positive, negative, or zero.)
d1729 1
a1729 1
        // Signal that the power is integral.
d1737 1
a1737 1
        // The integral power itself.
d1742 1
a1742 1
      // Record the largest integral power for each variable.
d1750 1
a1750 1
  // How many of all powers of each variable will there be?
d1753 1
a1753 1
    // Offset into dparm.
d1761 1
a1761 1
  // Expand dparm to store the extra powers.
d1770 1
a1770 1
  // No specialist de-distortions.
d1774 2
a1775 2
  // Translate Polynomial to TPD if possible, it's much faster.
  // However don't do it if the name was given as "Polynomial*".
d1783 1
a1783 1
//----------------------------------------------------------------------------
d1802 1
a1802 1
  // TPD distortion.
d1809 1
a1809 1
  // Find the number of parameters.
d1826 1
a1826 1
        // TPD may provide a polynomial approximation for the inverse.
d1838 1
a1838 1
        // Any radial terms?
d1849 1
a1849 1
      // Flag usage of auxiliary variables.
d1867 1
a1867 1
        // No inverse polynomial.
d1871 1
a1871 1
      // First degree.
d1875 1
a1875 1
      // Second degree.
d1879 1
a1879 1
      // Third degree.
d1883 1
a1883 1
      // Fourth degree.
d1887 1
a1887 1
      // Fifth degree.
d1891 1
a1891 1
      // Sixth degree.
d1895 1
a1895 1
      // Seventh degree.
d1899 1
a1899 1
      // Eighth degree.
d1903 1
a1903 1
      // Ninth degree.
d1912 2
a1913 2
  // disx2p() only uses the inverse TPD, if present, to provide a better
  // zeroth approximation.
d1918 5
a1922 5
// These iparm indices are specific to TPD.
#define I_TPDNCO  3	// No. of TPD coefficients, forward...
#define I_TPDINV  4	// ...and inverse.
#define I_TPDAUX  5	// True if auxiliary variables are used.
#define I_TPDRAD  6	// True if the radial variable is used.
d1925 1
a1925 1
  // Record indexing parameters.
d1933 1
a1933 1
  // The first three are more widely used.
d1938 1
a1938 1
  // Number of TPD coefficients.
d1942 1
a1942 1
  // Flag for presence of auxiliary variables.
d1945 1
a1945 1
  // Flag for presence of radial terms.
d1949 1
a1949 1
  // Allocate memory for the polynomial coefficients and fill it.
d1954 1
a1954 1
  // Set default auxiliary coefficients.
d1967 1
a1967 1
      // Auxiliary variables.
d2011 1
a2011 1
//----------------------------------------------------------------------------
d2034 1
a2034 1
  // Initialize.
d2042 1
a2042 1
  // Check the number of independent variables, no more than two.
d2046 1
a2046 1
  // Check auxiliaries: only one is allowed...
d2050 1
a2050 1
    // ...and it must be radial.
d2059 1
a2059 1
  // Check powers...
d2066 1
a2066 1
      // ...they must be positive integral.
d2074 1
a2074 1
    // The polynomial degree can't be greater than 9.
d2078 1
a2078 1
      // Likewise for the radial variable.
d2084 1
a2084 1
        // Can't mix the radial and other terms.
d2087 1
a2087 1
        // Can't have even powers of the radial variable.
d2099 1
a2099 1
  // OK, it ticks all the boxes.  Now translate it.
d2130 1
a2130 1
  // No specialist de-distortions.
d2133 1
a2133 1
  // Record indexing parameters.
d2139 1
a2139 1
  // The first three are more widely used.
d2144 1
a2144 1
  // Number of TPD coefficients.
d2148 1
a2148 1
  // No auxiliary variables yet.
d2151 1
a2151 1
  // Flag for presence of radial terms.
d2155 1
a2155 1
  // Allocate memory for the polynomial coefficients and fill it.
d2164 1
a2164 1
      // The radial variable.
d2184 1
a2184 1
      // The independent variables.
d2200 1
a2200 1
  // Switch from Polynomial to TPD.
d2209 1
a2209 1
//----------------------------------------------------------------------------
d2222 1
a2222 1
  // Initialize.
d2226 1
a2226 1
  // TPV "projection".
d2229 1
a2229 1
  // TPV computes corrected coordinates.
d2237 1
a2237 1
  // Find the number of parameters.
d2251 1
a2251 1
        // Any radial terms?
d2270 1
a2270 1
  // TPD is going to do the dirty work.
d2272 1
a2272 1
    // First degree.
d2276 1
a2276 1
    // Second degree.
d2280 1
a2280 1
    // Third degree.
d2284 1
a2284 1
    // Fourth degree.
d2288 1
a2288 1
    // Fifth degree.
d2292 1
a2292 1
    // Sixth degree.
d2296 1
a2296 1
    // Seventh degree.
d2300 1
a2300 1
    // Could go to ninth degree, but that wouldn't be legit.
d2305 1
a2305 1
  // No specialist de-distortions.
d2308 1
a2308 1
  // Record indexing parameters.
d2314 1
a2314 1
  // The first three are more widely used.
d2319 1
a2319 1
  // Number of TPD coefficients.
d2323 1
a2323 1
  // TPV never needs auxiliary variables.
d2326 1
a2326 1
  // Flag for presence of radial terms.
d2330 1
a2330 1
  // Allocate memory for the polynomial coefficients and fill it.
d2341 1
a2341 1
    // One-to-one correspondence between TPV and TPD coefficients.
d2351 1
a2351 1
//----------------------------------------------------------------------------
d2376 1
a2376 1
  // Initialize.
d2380 1
a2380 1
  // Simple Imaging Polynomial.
d2384 1
a2384 1
  // SIP computes an additive correction.
d2392 1
a2392 1
  // Find the polynomial degree, at least 1 for the forward function.
d2407 1
a2407 1
        // SIP uses a polynomial approximation for the inverse.
d2436 1
a2436 1
  // TPD is going to do the dirty work.
d2471 2
a2472 2
  // SIP uses a polynomial approximation to the inverse.  It's not very
  // accurate but may provide disx2p() with a better zeroth approximation.
d2477 1
a2477 1
  // Record indexing parameters.
d2485 1
a2485 1
  // The first three are more widely used.
d2490 1
a2490 1
  // Number of TPD coefficients.
d2494 1
a2494 1
  // SIP never needs auxiliary variables.
d2497 1
a2497 1
  // SIP never needs the radial terms.
d2501 1
a2501 1
  // Allocate memory for the polynomial coefficients and fill it.
d2522 1
a2522 1
      // Map to TPD coefficient number.
d2533 1
a2533 1
//----------------------------------------------------------------------------
d2547 1
a2547 1
  // Initialize.
d2551 1
a2551 1
  // Digitized Sky Survey.
d2555 1
a2555 1
  // DSS computes corrected coordinates.
d2563 1
a2563 1
  // Safe to assume the polynomial degree is 5 (or less).
d2567 1
a2567 1
  // No specialist de-distortions.
d2571 1
a2571 1
  // Record indexing parameters.
d2579 1
a2579 1
  // The first three are more widely used.
d2584 1
a2584 1
  // Number of TPD coefficients.
d2588 1
a2588 1
  // DSS always needs auxiliary variables.
d2591 1
a2591 1
  // DSS never needs the radial terms.
d2595 1
a2595 1
  // Allocate memory for the polynomial coefficients and fill it.
d2600 2
a2601 2
  // This translation follows WCS Paper IV, Sect. 5.2 using the same
  // variable names.  Find A1, A2, A3, B1, B2, and B3.
d2642 1
a2642 1
  // Coefficients for the auxiliary variables.
d2652 1
a2652 1
    // Change the sign of S for scaling the A coefficients.
d2664 1
a2664 1
  // Translate DSS coefficients to TPD.
d2674 1
a2674 1
      // Skip zero coefficients.
d2680 1
a2680 1
      // Apply the coefficient scale factor.
d2728 2
a2729 2
  // The DSS polynomial doesn't have 4th degree terms, and the 5th degree
  // coefficient is often zero.
d2738 1
a2738 1
//----------------------------------------------------------------------------
d2769 1
a2769 1
  // Initialize.
d2773 1
a2773 1
  // WAT (TNX or ZPX) Polynomial.
d2777 1
a2777 1
  // WAT computes an additive correction.
d2785 1
a2785 1
  // Find the polynomial degree (at least 1), kind, and domain.
d2839 1
a2839 1
  // TPD is going to do the dirty work.
d2842 1
a2842 1
    // First degree.
d2846 1
a2846 1
    // Second degree.
d2850 1
a2850 1
    // Third degree.
d2854 1
a2854 1
    // Fourth degree.
d2858 1
a2858 1
    // Fifth degree.
d2862 1
a2862 1
    // Sixth degree.
d2866 1
a2866 1
    // Seventh degree.
d2870 1
a2870 1
    // Eighth degree.
d2874 1
a2874 1
    // Ninth degree.
d2879 1
a2879 1
  // No specialist de-distortions.
d2883 1
a2883 1
  // Record indexing parameters.
d2893 1
a2893 1
  // The first three are more widely used.
d2898 1
a2898 1
  // Number of TPD coefficients.
d2902 1
a2902 1
  // The Chebyshev and Legendre polynomials use auxiliary variables.
d2905 1
a2905 1
  // WAT never needs the radial terms.
d2909 1
a2909 1
  // Allocate memory for the polynomial coefficients and fill it.
d2917 1
a2917 1
  // Coefficients for the auxiliary variables.
d2945 1
a2945 1
  // Unpack the polynomial coefficients.
d2960 1
a2960 1
        // Monomial coefficient, maps simply to TPD coefficient number.
d2965 2
a2966 2
        // Coefficient of the product of two Chebyshev or two Legendre
        // polynomials.  Find the corresponding monomial coefficients.
d2987 3
a2989 3
//----------------------------------------------------------------------------
// Compute the coefficients of Chebyshev or Legendre polynomials of degree
// m and n.
d2999 1
a2999 1
  // Allocate work arrays.
d3014 1
a3014 1
      // Cyclic buffer indices.
d3041 1
a3041 1
//----------------------------------------------------------------------------
d3057 1
a3057 1
  // Avert nuisance compiler warnings about unused parameters.
d3060 1
a3060 1
  // Check for zeroes.
d3068 1
a3068 1
  // Working memory for auxiliaries &c. was allocated at the end of p[].
d3071 1
a3071 1
  // Compute the auxiliary variables.
d3085 1
a3085 1
    // Check for zeroes.
d3093 1
a3093 1
  // Compute all required integral powers of the variables.
d3115 1
a3115 1
  // Loop for each term of the polynomial.
d3123 1
a3123 1
    // Loop over all variables.
d3128 1
a3128 1
        // Nothing (zero power).
d3131 1
a3131 1
        // Integral power.
d3133 1
a3133 1
          // Negative.
d3136 1
a3136 1
          // Positive.
d3141 1
a3141 1
        // Fractional power.
d3159 1
a3159 1
//----------------------------------------------------------------------------
d3179 1
a3179 1
  // Auxiliary variables?
d3189 1
a3189 1
  // First degree.
d3196 1
a3196 1
  // Radial terms?
d3207 1
a3207 1
//----------------------------------------------------------------------------
d3227 1
a3227 1
  // Auxiliary variables?
d3237 1
a3237 1
  // Second degree.
d3246 1
a3246 1
  // Radial terms?
d3257 1
a3257 1
//----------------------------------------------------------------------------
d3277 1
a3277 1
  // Auxiliary variables?
d3287 1
a3287 1
  // Third degree.
d3297 1
a3297 1
  // Radial terms?
d3308 1
a3308 1
//----------------------------------------------------------------------------
d3328 1
a3328 1
  // Auxiliary variables?
d3338 1
a3338 1
  // Fourth degree.
d3349 1
a3349 1
  // Radial terms?
d3360 1
a3360 1
//----------------------------------------------------------------------------
d3380 1
a3380 1
  // Auxiliary variables?
d3390 1
a3390 1
  // Fifth degree.
d3402 1
a3402 1
  // Radial terms?
d3413 1
a3413 1
//----------------------------------------------------------------------------
d3433 1
a3433 1
  // Auxiliary variables?
d3443 1
a3443 1
  // Sixth degree.
d3456 1
a3456 1
  // Radial terms?
d3467 1
a3467 1
//----------------------------------------------------------------------------
d3487 1
a3487 1
  // Auxiliary variables?
d3497 1
a3497 1
  // Seventh degree.
d3511 1
a3511 1
  // Radial terms?
d3522 1
a3522 1
//----------------------------------------------------------------------------
d3542 1
a3542 1
  // Auxiliary variables?
d3552 1
a3552 1
  // Eighth degree.
d3567 1
a3567 1
  // Radial terms?
d3578 1
a3578 1
//----------------------------------------------------------------------------
d3598 1
a3598 1
  // Auxiliary variables?
d3608 1
a3608 1
  // Ninth degree.
d3624 1
a3624 1
  // Radial terms?
@


7.3.1.3
log
@Augmented commenting for the historical distortion functions.  No
functional changes.
@
text
@d24 1
a24 1
  $Id: dis.c,v 7.3.1.2 2020/08/17 11:19:09 mcalabre Exp mcalabre $
d1098 1
a1098 1
        // Distortion function computes corrected coordinates directly.
d1187 1
a1187 1
        // Inverse distortion function computes corrected coordinates directly.
d2228 1
a2228 2
  // TPV is a sequent distortion, applied to intermediate world coordinates
  // (normally used with CDi_ja).  It computes corrected coordinates directly.
d2383 1
a2383 1
  // SIP is a prior distortion that computes an additive correction.
d2554 1
a2554 2
  // DSS is translated into a sequent distortion, applied to intermediate
  // pixel coordinates.  It computes corrected coordinates directly.
d2776 1
a2776 2
  // WAT is a sequent distortion, applied to intermediate world coordinates
  // (normally used with CDi_ja).  It computes an additive correction.
@


7.3.1.4
log
@Updated date in copyright notice.
@
text
@d3 1
a3 1
  Copyright (C) 1995-2021, Mark Calabretta
d24 1
a24 1
  $Id: dis.c,v 7.3.1.3 2020/09/21 08:25:53 mcalabre Exp mcalabre $
@


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


7.3.1.6
log
@In tpdset(), added a reminder that the iparm indexes have matching
definitions in wcshdr.c.
@
text
@d22 1
a22 1
  $Id: dis.c,v 7.3.1.5 2021/01/28 12:29:30 mcalabre Exp mcalabre $
d1915 1
a1915 1
// These iparm indices are specific to TPD (matching definitions in wcshdr.c).
@


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: dis.c,v 7.1.1.1 2019/12/31 13:28:19 mcalabre Exp mcalabre $
@


7.2.1.1
log
@WCSLIB 7.2 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 6.4.1.3 2019/12/31 03:28:03 mcalabre Exp mcalabre $
@


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


6.4
log
@WCSLIB 6.4
@
text
@d3 2
a4 2
  WCSLIB 6.4 - an implementation of the FITS WCS standard.
  Copyright (C) 1995-2019, Mark Calabretta
d25 1
a25 1
  $Id: dis.c,v 6.3.1.1 2019/07/12 07:34:37 mcalabre Exp mcalabre $
d81 1
a81 1
/* The first four iparm indices have meanings common to all distortion      */
a85 3
#define I_DOCORR  3	/* True if the distortion function computes a
			   correction to be applied to the coordinates (else
			   it computes the corrected coordinates directy).  */
d204 3
a207 1
      dis->Nhat   = 0x0;
d385 5
a389 1
    /* Recall that these were allocated in bulk by disset(). */
a394 1
    if (dis->Nhat)   free(dis->Nhat);
d415 2
a417 1
  dis->Nhat   = 0x0;
d484 2
a485 1
  WCSPRINTF_PTR("      axmap: ", dis->axmap, "\n");
d487 1
a487 9
    wcsprintf(" axmap[%d][]:", j);
    for (jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("%6d", dis->axmap[j][jhat]);
    }
    wcsprintf("\n            ");
    for (jhat = naxis; jhat < 2*naxis; jhat++) {
      wcsprintf("%6d", dis->axmap[j][jhat]);
    }
    wcsprintf("\n");
d489 1
d498 9
d733 4
a736 1
      /* Recall that axmap, offset, and scale are allocated in bulk. */
a738 1
      free(dis->Nhat);
d753 1
a753 1
    if ((dis->axmap = calloc(naxis, sizeof(int *))) == 0x0) {
d758 1
a758 2
    /* Allocate axmap[][] in bulk and then carve it up. */
    if ((dis->axmap[0] = calloc(2*naxis*naxis, sizeof(int))) == 0x0) {
d763 4
a766 2
    for (j = 1; j < naxis; j++) {
      dis->axmap[j] = dis->axmap[j-1] + 2*naxis;
d769 1
a769 1
    if ((dis->Nhat = calloc(naxis, sizeof(int *))) == 0x0) {
d774 5
a783 1
    /* Allocate offset[][] in bulk and then carve it up. */
d793 1
a798 1
    /* Allocate scale[][] in bulk and then carve it up. */
d837 7
a843 1
  for (jhat = 0; jhat < 2*naxis*naxis; jhat++) {
a846 1
  memset(dis->Nhat,      0, naxis*sizeof(int));
d885 1
d887 7
a893 1
    if (strncmp(fp, "NAXES", 6) == 0) {
a921 3

    /* DOCORR should also be handled here but no space was provided for it
       in disprm. */
a976 6

    /* Construct the inverse axis map. */
    for (jhat = 0; jhat < Nhat; jhat++) {
      k = naxis + dis->axmap[j][jhat];
      dis->axmap[j][k] = jhat;
    }
d1095 1
a1095 1
      if (dis->iparm[j][I_DOCORR]) {
d1184 1
a1184 1
      if (dis->iparm[j][I_DOCORR]) {
d1524 16
a1539 16
#define I_NIDX    4	/* No. of indexes in iparm[].                       */
#define I_LENDP   5	/* Full (allocated) length of dparm[].              */
#define I_K       6	/* No. of auxiliary variables.                      */
#define I_M       7	/* No. of terms in the polynomial.                  */
#define I_NKPARM  8	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  9	/* No. of parameters used to define each term.      */
#define I_NVAR   10	/* No. of independent + auxiliary variables.        */
#define I_MNVAR  11	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  12	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   13	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  14	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 15	/* iparm offset for max powers.                     */
#define I_DPOFF  16	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  17	/* iparm offset for flags.                          */
#define I_IPOW   18	/* iparm offset for integral powers.                */
#define I_NPOLY  19
d1561 1
a1561 1
  /* Record the indexing parameters.  The first four are more widely used. */
a1564 1
  iparm[I_DOCORR] = 1;
d1607 1
a1607 4
    if (strcmp(fp, "DOCORR") == 0) {
      if (dpkeyi(keyp) == 0) iparm[I_DOCORR] = 0;

    } else if (strncmp(fp, "AUX.", 4) == 0) {
d1694 2
a1695 1
    } else if (strcmp(fp, "NAXES")  &&
d1791 1
a1791 1
  int    doaux, docorr, doradial, idis, idp, k, m, ncoeff[2], ndparm, niparm;
a1813 1
  docorr    = 1;
d1852 2
a1853 4
    } else if (strcmp(fp, "DOCORR") == 0) {
      if (dpkeyi(keyp) == 0) docorr = 0;

    } else if (strcmp(fp, "NAXES")  &&
d1919 5
a1923 5
#define I_TPDNCO  4	/* No. of TPD coefficients, forward...   */
#define I_TPDINV  5	/* ...and inverse.                       */
#define I_TPDAUX  6	/* True if auxiliary variables are used. */
#define I_TPDRAD  7	/* True if the radial variable is used.  */
#define I_NTPD    8
d1933 1
a1933 1
  /* The first four are more widely used. */
a1936 1
  dis->iparm[j][I_DOCORR] = docorr;
d2139 1
a2139 1
  /* The first four are more widely used. */
a2142 1
  tpd_iparm[I_DOCORR] = iparm[I_DOCORR];
d2229 2
d2314 1
a2314 1
  /* The first four are more widely used. */
a2317 1
  dis->iparm[j][I_DOCORR] = 0;
d2384 3
d2485 1
a2485 1
  /* The first four are more widely used. */
a2488 1
  dis->iparm[j][I_DOCORR] = 1;
d2555 3
d2571 1
a2571 1
 /* Record indexing parameters. */
d2579 1
a2579 1
  /* The first four are more widely used. */
a2582 1
  dis->iparm[j][I_DOCORR] = 0;
d2776 4
d2893 1
a2893 1
  /* The first four are more widely used. */
a2896 1
  iparm[I_DOCORR] = 1;
@


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


6.4.1.2
log
@The DOCORR record is now handled as a first-class value via disprm::docorr
rather than hiding it away in disprm::iparm.  Removed the inverse axis map
from disprm::axmap as it is no longer needed.
@
text
@d25 1
a25 1
  $Id: dis.c,v 6.4.1.1 2019/08/15 09:31:29 mcalabre Exp mcalabre $
d81 1
a81 1
/* The first three iparm indices have meanings common to all distortion     */
d86 3
d207 1
a207 1
      dis->docorr = 0x0;
a208 2

      dis->axmap  = 0x0;
d386 1
a386 5
    /* The remainder were allocated by disset(). */
    if (dis->docorr) free(dis->docorr);
    if (dis->Nhat)   free(dis->Nhat);

    /* Recall that axmap, offset, and scale were allocated in bulk. */
d392 1
d413 1
a413 1
  dis->docorr = 0x0;
a414 1
  dis->axmap  = 0x0;
d481 1
a481 2
  WCSPRINTF_PTR("     docorr: ", dis->docorr, "\n");
  wcsprintf("            ");
d483 9
a491 1
    wcsprintf("%6d", dis->docorr[j]);
a492 1
  wcsprintf("\n");
a500 9
  WCSPRINTF_PTR("      axmap: ", dis->axmap, "\n");
  for (j = 0; j < naxis; j++) {
    wcsprintf(" axmap[%d][]:", j);
    for (jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("%6d", dis->axmap[j][jhat]);
    }
    wcsprintf("\n");
  }

d727 1
a727 4
      free(dis->docorr);
      free(dis->Nhat);

      /* Noting that axmap, offset, and scale are allocated in bulk. */
d730 1
d745 1
a745 1
    if ((dis->docorr = calloc(naxis, sizeof(int *))) == 0x0) {
d750 2
a751 1
    if ((dis->Nhat = calloc(naxis, sizeof(int *))) == 0x0) {
d756 2
a757 4
    /* Allocate axmap[][] in bulk and then carve it up. */
    if ((dis->axmap = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d760 1
a760 1
    if ((dis->axmap[0] = calloc(naxis*naxis, sizeof(int))) == 0x0) {
a764 5
    for (j = 1; j < naxis; j++) {
      dis->axmap[j] = dis->axmap[j-1] + naxis;
    }

    /* Allocate offset[][] in bulk and then carve it up. */
d770 1
a779 1
    /* Allocate scale[][] in bulk and then carve it up. */
d785 1
d824 1
a824 7
  for (j = 0; j < naxis; j++) {
    dis->docorr[j] = 1;
  }

  memset(dis->Nhat, 0, naxis*sizeof(int));

  for (jhat = 0; jhat < naxis*naxis; jhat++) {
d828 1
a866 1
    /* Convert to 0-relative axis number. */
d868 1
a868 7

    if (strncmp(fp, "DOCORR", 7) == 0) {
      if (dpkeyi(keyp) == 0) {
        dis->docorr[j] = 0;
      }

    } else if (strncmp(fp, "NAXES", 6) == 0) {
d897 3
d955 6
d1079 1
a1079 1
      if (dis->docorr[j]) {
d1168 1
a1168 1
      if (dis->docorr[j]) {
d1508 16
a1523 16
#define I_NIDX    3	/* No. of indexes in iparm[].                       */
#define I_LENDP   4	/* Full (allocated) length of dparm[].              */
#define I_K       5	/* No. of auxiliary variables.                      */
#define I_M       6	/* No. of terms in the polynomial.                  */
#define I_NKPARM  7	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  8	/* No. of parameters used to define each term.      */
#define I_NVAR    9	/* No. of independent + auxiliary variables.        */
#define I_MNVAR  10	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  11	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   12	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  13	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 14	/* iparm offset for max powers.                     */
#define I_DPOFF  15	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  16	/* iparm offset for flags.                          */
#define I_IPOW   17	/* iparm offset for integral powers.                */
#define I_NPOLY  18
d1545 1
a1545 1
  /* Record the indexing parameters.  The first three are more widely used. */
d1549 1
d1592 4
a1595 1
    if (strncmp(fp, "AUX.", 4) == 0) {
d1682 1
a1682 2
    } else if (strcmp(fp, "DOCORR") &&
               strcmp(fp, "NAXES")  &&
d1778 1
a1778 1
  int    doaux, doradial, idis, idp, k, m, ncoeff[2], ndparm, niparm;
d1801 1
d1840 4
a1843 2
    } else if (strcmp(fp, "DOCORR") &&
               strcmp(fp, "NAXES")  &&
d1909 5
a1913 5
#define I_TPDNCO  3	/* No. of TPD coefficients, forward...   */
#define I_TPDINV  4	/* ...and inverse.                       */
#define I_TPDAUX  5	/* True if auxiliary variables are used. */
#define I_TPDRAD  6	/* True if the radial variable is used.  */
#define I_NTPD    7
d1923 1
a1923 1
  /* The first three are more widely used. */
d1927 1
d2130 1
a2130 1
  /* The first three are more widely used. */
d2134 1
a2220 2
  /* TPV computes corrected coordinates. */
  dis->docorr[j] = 0;
d2304 1
a2304 1
  /* The first three are more widely used. */
d2308 1
a2374 3
  /* SIP computes an additive correction. */
  dis->docorr[j] = 1;

d2473 1
a2473 1
  /* The first three are more widely used. */
d2477 1
a2543 3
  /* DSS computes corrected coordinates. */
  dis->docorr[j] = 0;

d2557 1
a2557 1
  /* Record indexing parameters. */
d2565 1
a2565 1
  /* The first three are more widely used. */
d2569 1
a2762 4

  /* WAT computes an additive correction. */
  dis->docorr[j] = 1;

d2876 1
a2876 1
  /* The first three are more widely used. */
d2880 1
@


6.4.1.3
log
@Updated date in copyright notice.
@
text
@d4 1
a4 1
  Copyright (C) 1995-2020, Mark Calabretta
d25 1
a25 1
  $Id: dis.c,v 6.4.1.2 2019/12/01 03:53:46 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: dis.c,v 6.2.1.6 2019/07/09 08:46:04 mcalabre Exp mcalabre $
@


6.3.1.1
log
@WCSLIB 6.3 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 6.1.1.1 2018/10/19 08:36:15 mcalabre Exp mcalabre $
d86 3
a88 1
#define I_DOCORR  3	/* True if distortion func computes a correction.   */
d197 3
d201 1
a201 4
  if (dis->flag != -1) {
    if (dis->err) free(dis->err);
  }
  dis->err = 0x0;
d312 4
a315 1
  memset(dis->dtype,  0, naxis*sizeof(char [72]));
d317 7
a323 2
  memset(dis->dp,     0, ndpmax*sizeof(struct dpkey));
  memset(dis->maxdis, 0, naxis*sizeof(double));
a404 2

    if (dis->err) free(dis->err);
d423 1
a423 1
  dis->err  = 0x0;
d717 8
a724 1
  /* Allocate memory for derived parameters and work arrays. */
a735 5
      for (j = 0; j < dis->i_naxis; j++) {
        /* Memory allocated separately for each axis. */
        if (dis->iparm[j]) free(dis->iparm[j]);
        if (dis->dparm[j]) free(dis->dparm[j]);
      }
d1080 1
a1080 1
        /* Distortion function computes a correction. */
d1083 1
d1169 1
a1169 1
        /* Inverse distortion function computes a correction. */
d1172 1
d1549 1
a1549 1
  iparm[I_DOCORR] = 0;
d1592 2
a1593 4
    if (strncmp(fp, "DOCORR:", 7) == 0) {
      fp += 7;
      sscanf(fp, "%d", &k);
      if (k) iparm[I_DOCORR] = 1;
d1801 1
a1801 1
  docorr    = 0;
d1840 2
a1841 5
    } else if (strncmp(fp, "DOCORR:", 7) == 0) {
      fp += 7;
      sscanf(fp, "%d", &k);
      if (k) docorr = 1;

d1910 1
a1910 1
#define I_TPDINV  5     /* ...and inverse.                       */
d2361 1
a2361 2
  int    deg, degree[2], idis, idp, jhat, naxis, ncoeff[2], ndparm, niparm,
         p, q;
d2477 1
a2477 1
  dis->iparm[j][I_DOCORR] = 0;
a2515 14
  }

  /* Account for the fact that the SIP distortion provides an additive    */
  /* correction to the offset of the pixel coordinate from CRPIX, whereas */
  /* we expect the distortion function to provide the actual value of the */
  /* distorted pixel coordinate.                                          */
  naxis = dis->naxis;
  jhat  = dis->axmap[j][naxis+j];
  idis  = jhat + 1;
  dis->dparm[j][0] = dis->offset[j][jhat];
  dis->dparm[j][idis] += 1.0;
  if (degree[1] > 0) {
    dis->dparm[j][ncoeff[0]] = dis->offset[j][jhat];
    dis->dparm[j][ncoeff[0]+idis] += 1.0;
@


6.2.1.1
log
@WCSLIB 6.2 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 6.2.1.1 2018/10/20 10:04:15 mcalabre Exp mcalabre $
@


6.2.1.3
log
@Fixed the Polynomial and TPD distortions so that they are now considered to
return an additive correction to be applied to the given coordinates, so
iparm[I_DOCORR] defaults to 1 in polyset() and tpdset(), but this can be
overridden by setting DPja.DOCORR = 0.  Also amended sipset() accordingly.
@
text
@d25 1
a25 1
  $Id: dis.c,v 6.2.1.2 2019/05/10 01:56:50 mcalabre Exp mcalabre $
d86 1
a86 3
#define I_DOCORR  3	/* True if distortion func computes a correction to */
                        /* be applied to the coordinates (else it computes  */
			/* the corrected coordinates directy).              */
d1070 1
a1070 1
        /* Distortion function computes a correction to be applied. */
a1072 1
        /* Distortion function computes corrected coordinates. */
d1158 1
a1158 1
        /* Inverse distortion function computes a correction to be applied. */
a1160 1
        /* Inverse distortion function computes corrected coordinates. */
d1537 1
a1537 1
  iparm[I_DOCORR] = 1;
d1580 4
a1583 2
    if (strcmp(fp, "DOCORR") == 0) {
      if (dpkeyi(keyp) == 0) iparm[I_DOCORR] = 0;
d1791 1
a1791 1
  docorr    = 1;
d1830 5
a1834 2
    } else if (strcmp(fp, "DOCORR") == 0) {
      if (dpkeyi(keyp) == 0) docorr = 0;
d2354 2
a2355 1
  int    deg, degree[2], idis, idp, ncoeff[2], ndparm, niparm, p, q;
d2471 1
a2471 1
  dis->iparm[j][I_DOCORR] = 1;
d2510 14
@


6.2.1.4
log
@In disinit() and disfree(), 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: dis.c,v 6.2.1.3 2019/07/07 09:17:19 mcalabre Exp mcalabre $
d86 3
a88 3
#define I_DOCORR  3	/* True if the distortion function computes a
			   correction to be applied to the coordinates (else
			   it computes the corrected coordinates directy).  */
d199 1
a199 1
    wcserr_clear(err);
d201 1
d398 1
a398 1
    wcserr_clear(&(dis->err));
d1902 1
a1902 1
#define I_TPDINV  5	/* ...and inverse.                       */
@


6.2.1.5
log
@In disinit(), don't try to memset() zero bytes on a null pointer, -fsanitize
doesn't like it.
@
text
@d25 1
a25 1
  $Id: dis.c,v 6.2.1.4 2019/07/08 03:23:14 mcalabre Exp mcalabre $
d311 1
a311 4
  if (naxis) {
    memset(dis->dtype, 0, naxis*sizeof(char [72]));
  }

d313 2
a314 7
  if (ndpmax) {
    memset(dis->dp, 0, ndpmax*sizeof(struct dpkey));
  }

  if (naxis) {
    memset(dis->maxdis, 0, naxis*sizeof(double));
  }
@


6.2.1.6
log
@Fixed the initialisation of error message handling in disinit().  In
disset(), memory allocated separately for each axis in the disprm::iparm
and disprm::dparm arrays must always be freed, since the various specialised
functions (polyset(), tpdset(), etc.) will always allocate the memory they
need on top of them.
@
text
@d25 1
a25 1
  $Id: dis.c,v 6.2.1.5 2019/07/08 14:08:14 mcalabre Exp mcalabre $
d197 3
a199 2
  if (dis->flag == -1) {
    dis->err = 0x0;
a200 2
  err = &(dis->err);
  wcserr_clear(err);
d404 2
d424 1
a424 1
  wcserr_clear(&(dis->err));
d718 1
a718 8
  /* Free memory allocated separately for each axis. */
  for (j = 0; j < dis->i_naxis; j++) {
    if (dis->iparm[j]) free(dis->iparm[j]);
    if (dis->dparm[j]) free(dis->dparm[j]);
  }

  /* Allocate or reallocate memory, if necessary, for derived parameter and
     work arrays sized according to the number of axes. */
d730 5
@


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: dis.c,v 5.20.1.1 2018/10/05 05:33:33 mcalabre Exp mcalabre $
@


6.1.1.1
log
@WCSLIB 6.1 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 5.19.1.2 2018/10/05 04:52:42 mcalabre Exp mcalabre $
@


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


5.19
log
@WCSLIB 5.19
@
text
@d3 1
a3 1
  WCSLIB 5.19 - an implementation of the FITS WCS standard.
d25 1
a25 1
  $Id: dis.c,v 5.18.1.5 2018/07/25 06:18:06 mcalabre Exp mcalabre $
d149 24
d859 1
a859 1
      Nhat = wcsutil_dpkey_int(keyp);
d877 1
a877 1
      dis->axmap[j][jhat-1] = wcsutil_dpkey_int(keyp) - 1;
d881 1
a881 1
      dis->offset[j][jhat-1] = wcsutil_dpkey_double(keyp);
d885 1
a885 1
      dis->scale[j][jhat-1] = wcsutil_dpkey_double(keyp);
d1473 1
a1473 1
      K = wcsutil_dpkey_int(keyp);
d1475 1
a1475 1
      M = wcsutil_dpkey_int(keyp);
d1620 1
a1620 1
      dparm[i] = wcsutil_dpkey_double(keyp);
d1639 1
a1639 1
        dparm[i] = wcsutil_dpkey_double(keyp);
d1651 1
a1651 1
        power = wcsutil_dpkey_double(keyp);
d1664 1
a1664 1
        power = wcsutil_dpkey_double(keyp);
d1978 1
a1978 1
      dis->dparm[j][idis] = wcsutil_dpkey_double(keyp);
d1988 1
a1988 1
      dis->dparm[j][idis+k] = wcsutil_dpkey_double(keyp);
d2328 1
a2328 1
      dis->dparm[j][k] = wcsutil_dpkey_double(keyp);
d2508 1
a2508 1
      dis->dparm[j][idis] = wcsutil_dpkey_double(keyp);
d2608 1
a2608 1
          A1 = wcsutil_dpkey_double(keyp);
d2610 1
a2610 1
          B1 = wcsutil_dpkey_double(keyp);
d2614 1
a2614 1
          A2 = wcsutil_dpkey_double(keyp);
d2616 1
a2616 1
          B2 = wcsutil_dpkey_double(keyp);
d2620 1
a2620 1
          A3 = wcsutil_dpkey_double(keyp);
d2622 1
a2622 1
          B3 = wcsutil_dpkey_double(keyp);
d2670 1
a2670 1
      if ((coeff = wcsutil_dpkey_double(keyp)) == 0.0) continue;
d2804 1
a2804 1
        kind = wcsutil_dpkey_int(keyp);
d2807 1
a2807 1
        xmin = wcsutil_dpkey_double(keyp);
d2810 1
a2810 1
        xmax = wcsutil_dpkey_double(keyp);
d2813 1
a2813 1
        ymin = wcsutil_dpkey_double(keyp);
d2816 1
a2816 1
        ymax = wcsutil_dpkey_double(keyp);
d2954 1
a2954 1
        dparm[idis] = wcsutil_dpkey_double(keyp);
d2959 1
a2959 1
        coeff = wcsutil_dpkey_double(keyp);
@


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


5.19.1.2
log
@Added dpkeyi() and dpkeyd().  wcsutil_dpkey_int() -> dpkeyi(),
wcsutil_dpkey_double() -> dpkeyd().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.19.1.1 2018/07/26 15:41:40 mcalabre Exp mcalabre $
a148 24
int dpkeyi(const struct dpkey *dp)

{
  if (dp->type != 0) {
    return (int)dp->value.f;
  }

  return dp->value.i;
}

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

double dpkeyd(const struct dpkey *dp)

{
  if (dp->type == 0) {
    return (double)dp->value.i;
  }

  return dp->value.f;
}

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

d835 1
a835 1
      Nhat = dpkeyi(keyp);
d853 1
a853 1
      dis->axmap[j][jhat-1] = dpkeyi(keyp) - 1;
d857 1
a857 1
      dis->offset[j][jhat-1] = dpkeyd(keyp);
d861 1
a861 1
      dis->scale[j][jhat-1] = dpkeyd(keyp);
d1449 1
a1449 1
      K = dpkeyi(keyp);
d1451 1
a1451 1
      M = dpkeyi(keyp);
d1596 1
a1596 1
      dparm[i] = dpkeyd(keyp);
d1615 1
a1615 1
        dparm[i] = dpkeyd(keyp);
d1627 1
a1627 1
        power = dpkeyd(keyp);
d1640 1
a1640 1
        power = dpkeyd(keyp);
d1954 1
a1954 1
      dis->dparm[j][idis] = dpkeyd(keyp);
d1964 1
a1964 1
      dis->dparm[j][idis+k] = dpkeyd(keyp);
d2304 1
a2304 1
      dis->dparm[j][k] = dpkeyd(keyp);
d2484 1
a2484 1
      dis->dparm[j][idis] = dpkeyd(keyp);
d2584 1
a2584 1
          A1 = dpkeyd(keyp);
d2586 1
a2586 1
          B1 = dpkeyd(keyp);
d2590 1
a2590 1
          A2 = dpkeyd(keyp);
d2592 1
a2592 1
          B2 = dpkeyd(keyp);
d2596 1
a2596 1
          A3 = dpkeyd(keyp);
d2598 1
a2598 1
          B3 = dpkeyd(keyp);
d2646 1
a2646 1
      if ((coeff = dpkeyd(keyp)) == 0.0) continue;
d2780 1
a2780 1
        kind = dpkeyi(keyp);
d2783 1
a2783 1
        xmin = dpkeyd(keyp);
d2786 1
a2786 1
        xmax = dpkeyd(keyp);
d2789 1
a2789 1
        ymin = dpkeyd(keyp);
d2792 1
a2792 1
        ymax = dpkeyd(keyp);
d2930 1
a2930 1
        dparm[idis] = dpkeyd(keyp);
d2935 1
a2935 1
        coeff = dpkeyd(keyp);
@


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: dis.c,v 5.17.1.5 2018/01/10 08:25:34 mcalabre Exp mcalabre $
d303 1
a303 1
  int naxis, ndp, status;
d534 1
a534 1
      wcsutil_fptr2str((int (*)(void))dis->disp2x[j], hext));
d562 1
a562 1
      wcsutil_fptr2str((int (*)(void))dis->disx2p[j], hext));
d678 4
d1743 1
a1743 1
  char   *fp, id[16];
d2177 1
a2177 1
  char   *fp, id[16];
d2329 1
a2329 1
  char   *fp, id[16];
d2513 1
a2513 1
  char   *fp, id[16];
d2731 1
a2731 1
  char   *fp, id[20];
d3024 3
@


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


5.18.1.2
log
@In discpy(), removed unused variable ndp.
In tpdset(), tpvset(), sipset(), dssset(), and watset(), increased the size
of the sprintf() output buffer, id[], to avert -Wformat-overflow warnings
from gcc 8.1.0 (with -DFORTIFY_SOURCE=2).
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.18.1.1 2018/01/10 08:33:04 mcalabre Exp mcalabre $
d303 1
a303 1
  int naxis, status;
d1739 1
a1739 1
  char   *fp, id[32];
d2173 1
a2173 1
  char   *fp, id[32];
d2325 1
a2325 1
  char   *fp, id[32];
d2509 1
a2509 1
  char   *fp, id[32];
d2727 1
a2727 1
  char   *fp, id[32];
@


5.18.1.3
log
@Changed function prototype of wcsutil_fptr2str() to avert
-Wcast-function-type warnings from gcc 8.1.0.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.18.1.2 2018/07/24 13:56:53 mcalabre Exp mcalabre $
d534 1
a534 1
      wcsutil_fptr2str((void (*)(void))dis->disp2x[j], hext));
d562 1
a562 1
      wcsutil_fptr2str((void (*)(void))dis->disx2p[j], hext));
@


5.18.1.4
log
@In dispoly(), avert a nuisance compiler warning about an unused parameter
(gcc -Wunused-parameter).
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.18.1.3 2018/07/25 00:19:49 mcalabre Exp mcalabre $
a3019 3

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


5.18.1.5
log
@In disset(), avert a nuisance compiler warning about possible use of an
uninitialized variable (gcc -Wmaybe-uninitialized).
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.18.1.4 2018/07/25 01:09:39 mcalabre Exp mcalabre $
a677 4

    /* A Clayton's distortion.  Avert compiler warnings about possible use of
       uninitialized variables. */
    dpq = 0x0;
@


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: dis.c,v 5.16.1.2 2017/09/12 13:03:32 mcalabre Exp mcalabre $
d152 9
a160 1
  static const char *function = "disini";
d164 1
d167 3
d212 1
a212 1
      (NDPMAX && dis->dp == 0x0) ||
d218 1
a218 1
        dis->ndpmax  < NDPMAX)) {
d246 2
a247 2
        if (NDPMAX) {
          if ((dis->dp = calloc(NDPMAX, sizeof(struct dpkey))) == 0x0) {
d255 1
a255 1
        dis->ndpmax  = NDPMAX;
d288 1
a288 1
  memset(dis->dp,     0, NDPMAX*sizeof(struct dpkey));
d316 1
a316 4
  ndp = NDPMAX;
  NDPMAX = dissrc->ndpmax;

  if ((status = disini(alloc, naxis, disdst))) {
a319 2
  NDPMAX = ndp;

d341 1
a341 1
    /* Optionally allocated by disini() for given parameters. */
@


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


5.17.1.2
log
@Replace all direct references to NDPMAX with calls to disndp().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.17.1.1 2017/09/18 08:45:59 mcalabre Exp mcalabre $
a153 1
  int ndpmax;
a157 2
  ndpmax = disndp(-1);

d200 1
a200 1
      (ndpmax && dis->dp == 0x0) ||
d206 1
a206 1
        dis->ndpmax  < ndpmax)) {
d234 2
a235 2
        if (ndpmax) {
          if ((dis->dp = calloc(ndpmax, sizeof(struct dpkey))) == 0x0) {
d243 1
a243 1
        dis->ndpmax  = ndpmax;
d276 1
a276 1
  memset(dis->dp,     0, ndpmax*sizeof(struct dpkey));
d304 2
a305 2
  ndp = disndp(-1);
  disndp(dissrc->ndpmax);
d311 1
a311 1
  disndp(ndp);
@


5.17.1.3
log
@Added new function disinit(), with disini() now a thin wrapper over it.
Modified discpy() to use disinit() in place of disini().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.17.1.2 2017/12/04 04:42:32 mcalabre Exp mcalabre $
d152 1
a152 9
  return disinit(alloc, naxis, dis, -1);
}

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

int disinit(int alloc, int naxis, struct disprm *dis, int ndpmax)

{
  static const char *function = "disinit";
d154 1
a156 1
  /* Check inputs. */
d159 1
a159 2
  if (ndpmax < 0) ndpmax = disndp(-1);

d307 4
a310 1
  if ((status = disinit(alloc, naxis, disdst, dissrc->ndpmax))) {
d313 2
@


5.17.1.4
log
@Fixed a comment.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.17.1.3 2017/12/05 07:23:56 mcalabre Exp mcalabre $
d341 1
a341 1
    /* Optionally allocated by disinit() 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: dis.c,v 5.17.1.4 2017/12/05 21:13:08 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: dis.c,v 5.15.1.2 2017/01/15 04:13:33 mcalabre Exp mcalabre $
d3001 1
a3001 1
  int inverse,
@


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


5.16.1.2
log
@Renamed the first, unused argument of dispoly() from "inverse" to "dummy" to
make it clear that it is not used in this distortion routine.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.16.1.1 2017/01/15 04:28:59 mcalabre Exp mcalabre $
d3001 1
a3001 1
  int dummy,
@


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: dis.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: dis.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: dis.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: dis.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: dis.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: dis.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: dis.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: dis.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: dis.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: dis.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: dis.c,v 5.10.1.2 2015/10/18 08:58:15 mcalabre Exp mcalabre $
@


5.11.1.1
log
@WCSLIB 5.11 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 5.9.1.1 2015/07/21 09:28:07 mcalabre Exp mcalabre $
d2720 1
a2720 1
  char   *fp, id[16];
@


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


5.10.1.2
log
@Bug fix supplied by Ole Streicher: in watset(), char id[16] was undersized,
increase to char [20].
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.10.1.1 2015/10/09 08:22:35 mcalabre Exp mcalabre $
d2720 1
a2720 1
  char   *fp, id[20];
@


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: dis.c,v 5.8.1.2 2015/07/21 08:34:56 mcalabre Exp mcalabre $
@


5.9.1.1
log
@WCSLIB 5.9 development branch.
@
text
@d25 1
a25 1
  $Id: dis.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: dis.c,v 5.7.1.5 2015/07/08 10:01:04 mcalabre Exp mcalabre $
d1867 5
a1871 4
#define I_TPDNCO  4	/* No. of TPD coefficients.              */
#define I_TPDAUX  5	/* True if auxiliary variables are used. */
#define I_TPDRAD  6	/* True if the radial variable is used.  */
#define I_NTPD    7
d1889 1
d2096 1
d2270 1
d2440 1
d2526 3
d2546 1
d2857 1
d3126 1
a3126 1
  if (i[I_TPDNCO] != 4 || 2 < Nhat) {
d3174 1
a3174 1
  if (i[I_TPDNCO] != 7 || 2 < Nhat) {
d3224 1
a3224 1
  if (i[I_TPDNCO] != 12 || 2 < Nhat) {
d3275 1
a3275 1
  if (i[I_TPDNCO] != 17 || 2 < Nhat) {
d3327 1
a3327 1
  if (i[I_TPDNCO] != 24 || 2 < Nhat) {
d3380 1
a3380 1
  if (i[I_TPDNCO] != 31 || 2 < Nhat) {
d3434 1
a3434 1
  if (i[I_TPDNCO] != 40 || 2 < Nhat) {
d3489 1
a3489 1
  if (i[I_TPDNCO] != 49 || 2 < Nhat) {
d3545 1
a3545 1
  if (i[I_TPDNCO] != 60 || 2 < Nhat) {
@


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


5.8.1.2
log
@Make proper allowance for the possibility that the TPD and SIP forward and
inverse distortion polynomials may not be of the same degree.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.8.1.1 2015/07/08 11:07:18 mcalabre Exp mcalabre $
d1867 4
a1870 5
#define I_TPDNCO  4	/* No. of TPD coefficients, forward...   */
#define I_TPDINV  5     /* ...and inverse.                       */
#define I_TPDAUX  6	/* True if auxiliary variables are used. */
#define I_TPDRAD  7	/* True if the radial variable is used.  */
#define I_NTPD    8
a1887 1
  dis->iparm[j][I_TPDINV] = ncoeff[1];
a2093 1
  tpd_iparm[I_TPDINV] = 0;
a2266 1
  dis->iparm[j][I_TPDINV] = 0;
a2435 1
  dis->iparm[j][I_TPDINV] = ncoeff[1];
a2520 3
  /* No specialist de-distortions. */
  dis->disx2p[j] = 0x0;

a2537 1
  dis->iparm[j][I_TPDINV] = 0;
a2847 1
  iparm[I_TPDINV] = 0;
d3116 1
a3116 1
  if (i[I_TPDNCO+inverse] != 4 || 2 < Nhat) {
d3164 1
a3164 1
  if (i[I_TPDNCO+inverse] != 7 || 2 < Nhat) {
d3214 1
a3214 1
  if (i[I_TPDNCO+inverse] != 12 || 2 < Nhat) {
d3265 1
a3265 1
  if (i[I_TPDNCO+inverse] != 17 || 2 < Nhat) {
d3317 1
a3317 1
  if (i[I_TPDNCO+inverse] != 24 || 2 < Nhat) {
d3370 1
a3370 1
  if (i[I_TPDNCO+inverse] != 31 || 2 < Nhat) {
d3424 1
a3424 1
  if (i[I_TPDNCO+inverse] != 40 || 2 < Nhat) {
d3479 1
a3479 1
  if (i[I_TPDNCO+inverse] != 49 || 2 < Nhat) {
d3535 1
a3535 1
  if (i[I_TPDNCO+inverse] != 60 || 2 < Nhat) {
@


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: dis.c,v 5.6.1.6 2015/06/28 14:44:34 mcalabre Exp mcalabre $
d40 3
a42 2
const int POLYNOMIAL = 0;
const int TPD        = 1;
d52 1
a52 1
  "Failed to initialize distortion functions",
d59 29
d104 1
a104 1
  char *cp;
d108 14
a121 1
      sprintf(dp->field, "%s.%s", keyword, field);
d487 1
a487 1
      for (k = 0; k < dis->iparm[j][1]; k++) {
d504 1
a504 1
      for (k = 0; k < dis->iparm[j][2]; k++) {
d591 33
d816 1
a816 1
    if ((fp = strpbrk(keyp->field, ".")) == 0x0) {
d852 3
d954 14
d1034 6
a1039 1
      discrd[j] = dtmp;
d1122 6
a1127 1
      rawcrd[j] = rtmp;
d1431 1
a1431 1
    if ((fp = strpbrk(keyp->field, ".")) == 0x0) {
d1460 17
a1476 19
#define I_DTYPE   0	/* Distortion type code.                            */
#define I_NIPARM  1	/* Full (allocated) length of iparm[].              */
#define I_NDPARM  2	/* No. of parameters in dparm[], excl. work space.  */
#define I_NIDX    3	/* No. of indexes in iparm[].                       */
#define I_LENDP   4	/* Full (allocated) length of dparm[].              */
#define I_K       5	/* No. of auxiliary variables.                      */
#define I_M       6	/* No. of terms in the polynomial.                  */
#define I_NKPARM  7	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  8	/* No. of parameters used to define each term.      */
#define I_NVAR    9	/* No. of independent + auxiliary variables.        */
#define I_MNVAR  10	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  11	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   12	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  13	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 14	/* iparm offset for max powers.                     */
#define I_DPOFF  15	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  16	/* iparm offset for flags.                          */
#define I_IPOW   17	/* iparm offset for integral powers.                */
#define NIDX     18
d1478 2
a1479 2
  /* Add extra for integer exponents.  See "Optimization" below. */
  niparm = NIDX + (2 + 2*M)*nVar;
d1498 2
a1499 2
  /* Record the indexing parameters.  The first two are used by disprt(). */
  iparm[I_DTYPE]  = POLYNOMIAL;
d1502 3
a1504 1
  iparm[I_NIDX]   = NIDX;
d1543 1
a1543 1
    fp = strpbrk(keyp->field, ".") + 1;
d1545 6
a1550 1
    if (strncmp(fp, "AUX.", 4) == 0) {
d1559 1
a1559 1
      if ((fp = strpbrk(fp, ".")) == 0x0) {
d1596 1
a1596 1
      if ((fp = strpbrk(fp, ".")) == 0x0) {
d1652 1
a1652 1
  /*     NIDX indexing parameters, as above,                                */
d1727 233
d2047 1
d2081 1
a2081 1
  niparm = 5;
d2086 11
a2096 5
  /* The first three are required by disprt(). */
  tpd_iparm[0] = TPD;
  tpd_iparm[1] = niparm;
  tpd_iparm[2] = ndparm;
  tpd_iparm[3] = ndparm;
d2099 1
a2099 1
  tpd_iparm[4] = K;
d2158 1
a2158 7
int dispoly(
  int inverse,
  const int iparm[],
  const double dparm[],
  int Nhat,
  const double rawcrd[],
  double *discrd)
d2161 1
a2161 4
  const int *iflgp, *imaxp, *imaxpow, *ipowp;
  int    ip, ivar, jhat, k, m;
  const double *cptr, *dpolp, *pptr;
  double *aux, auxp0, *dvarpow, *dpowp, term, var;
d2163 4
a2166 7
  /* Check for zeroes. */
  for (jhat = 0; jhat < Nhat; jhat++) {
    if (rawcrd[jhat] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }
a2167 102
  /* Working memory for auxiliaries &c. was allocated at the end of p[]. */
  aux = (double *)(dparm + iparm[I_DAUX]);

  /* Compute the auxiliary variables. */
  for (k = 0; k < iparm[I_K]; k++) {
    cptr = dparm + k*iparm[I_NKPARM];
    pptr = cptr + (1+Nhat);

    aux[k] = *(cptr++);
    auxp0  = *(pptr++);

    for (jhat = 0; jhat < Nhat; jhat++) {
      aux[k] += *(cptr++)*pow(rawcrd[jhat], *(pptr++));
    }

    aux[k] = pow(aux[k], auxp0);

    /* Check for zeroes. */
    if (aux[k] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }


  /* Compute all required integral powers of the variables. */
  imaxpow = iparm + iparm[I_MAXPOW];
  dvarpow = (double *)(dparm + iparm[I_DVPOW]);

  imaxp = imaxpow;
  dpowp = dvarpow;
  for (jhat = 0; jhat < Nhat; jhat++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= rawcrd[jhat];
      *dpowp = var;
    }
  }

  for (k = 0; k < iparm[I_K]; k++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= aux[k];
      *dpowp = var;
    }
  }

  /* Loop for each term of the polynomial. */
  *discrd = 0.0;
  iflgp = iparm + iparm[I_FLAGS];
  ipowp = iparm + iparm[I_IPOW];
  dpolp = dparm + iparm[I_DPOLY];
  for (m = 0; m < iparm[I_M]; m++) {
    term = *(dpolp++);

    /* Loop over all variables. */
    imaxp = imaxpow;
    dpowp = dvarpow - 1;
    for (ivar = 0; ivar < iparm[I_NVAR]; ivar++) {
      if (*iflgp & 2) {
        /* Nothing (zero power). */

      } else if (*iflgp) {
        /* Integral power. */
        if (*ipowp < 0) {
          /* Negative. */
          term /= dpowp[*ipowp];
        } else {
          /* Positive. */
          term *= dpowp[*ipowp];
        }

      } else {
        /* Fractional power. */
        term *= pow(dpowp[0], *dpolp);
      }

      iflgp++;
      ipowp++;
      dpolp++;

      dpowp += *imaxp;
      imaxp++;
    }

    *discrd += term;
  }

  return 0;
}

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

int tpvset(int j, struct disprm *dis)

{
  static const char *function = "tpvset";

  char   *fp, id[16];
  int    doradial, idp, k, ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;
d2169 1
d2173 1
a2176 1
  /* TPV "projection". */
d2189 1
a2189 1
    fp = strpbrk(keyp->field, ".") + 1;
d2254 1
a2254 1
  niparm = 5;
d2259 11
a2269 5
  /* The first three are required by disprt(). */
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ndparm;
d2272 1
a2272 1
  dis->iparm[j][4] = doradial;
d2284 1
a2284 1
    fp = strpbrk(keyp->field, ".") + 1;
d2321 2
d2326 1
a2329 1
  /* Simple Imaging Polynomial. */
d2342 1
a2342 1
    fp = strpbrk(keyp->field, ".") + 1;
d2421 1
a2421 1
  niparm = 5;
a2425 1
  /* The first three are required by disprt(). */
d2427 12
a2438 4
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff[0];
d2441 1
a2441 1
  dis->iparm[j][4] = 0;
d2453 1
a2453 1
    fp = strpbrk(keyp->field, ".") + 1;
d2479 1
a2479 1
  dis->dparm[j][0]  = dis->offset[j][jhat];
d2492 1
a2492 1
int tpdset(int j, struct disprm *dis)
d2495 1
a2495 1
  static const char *function = "tpdset";
d2498 2
a2499 1
  int    doradial, idis, idp, k, ncoeff[2], ndparm, niparm;
a2501 1
  int (*(distpd[2]))(DISP2X_ARGS);
d2503 2
d2508 215
a2722 1
  sprintf(id, "TPD on axis %d", j+1);
d2724 2
d2727 1
a2727 2
  /* TPD distortion. */
  if (dis->Nhat[j] < 1 || 2 < dis->Nhat[j]) {
d2729 160
a2888 2
      "Axis map for %s must contain 1 or 2 entries, not %d", id,
      dis->Nhat[j]);
d2891 2
a2892 4
  /* Find the number of parameters. */
  ncoeff[0] = 0;
  ncoeff[1] = 0;
  doradial  = 0;
d2897 48
a2944 1
    fp = strpbrk(keyp->field, ".") + 1;
d2946 4
a2949 4
    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        idis = 0;
d2951 2
a2952 3
      } else if (strncmp(fp, "REV.", 4) == 0) {
        /* TPD may provide a polynomial approximation for the inverse. */
        idis = 1;
d2954 2
a2955 4
      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }
d2957 2
a2958 3
      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 59) {
        if (ncoeff[idis] < k+1) ncoeff[idis] = k+1;
d2960 15
a2974 3
        /* Any radial terms? */
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
a2975 4

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
d2977 1
d2979 2
a2980 7
    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
d2983 20
a3002 8
  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (idis = 0; idis < 2; idis++) {
    if (ncoeff[idis] <= 4) {
      if (idis) {
        /* No inverse polynomial. */
        break;
      }
d3004 5
a3008 38
      /* First degree. */
      ncoeff[idis] = 4;
      distpd[idis] = tpd1;
    } else if (ncoeff[idis] <= 7) {
      /* Second degree. */
      ncoeff[idis] = 7;
      distpd[idis] = tpd2;
    } else if (ncoeff[idis] <= 12) {
      /* Third degree. */
      ncoeff[idis] = 12;
      distpd[idis] = tpd3;
    } else if (ncoeff[idis] <= 17) {
      /* Fourth degree. */
      ncoeff[idis] = 17;
      distpd[idis] = tpd4;
    } else if (ncoeff[idis] <= 24) {
      /* Fifth degree. */
      ncoeff[idis] = 24;
      distpd[idis] = tpd5;
    } else if (ncoeff[idis] <= 31) {
      /* Sixth degree. */
      ncoeff[idis] = 31;
      distpd[idis] = tpd6;
    } else if (ncoeff[idis] <= 40) {
      /* Seventh degree. */
      ncoeff[idis] = 40;
      distpd[idis] = tpd7;
    } else if (ncoeff[idis] <= 49) {
      /* Eighth degree. */
      ncoeff[idis] = 49;
      distpd[idis] = tpd8;
    } else if (ncoeff[idis] <= 60) {
      /* Ninth degree. */
      ncoeff[idis] = 60;
      distpd[idis] = tpd9;
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid number of parameters (%d) for %s", ncoeff[idis], id);
d3012 14
a3025 4
  /* disx2p() only uses the inverse TPD, if present, to provide a better */
  /* zeroth approximation. */
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];
d3027 1
d3029 5
a3033 4
  /* Record indexing parameters. */
  niparm = 5;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
a3035 6
  /* The first three are required by disprt(). */
  ndparm = ncoeff[0] + ncoeff[1];
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff[0];
d3037 3
a3039 2
  /* Flag for presence of radial terms. */
  dis->iparm[j][4] = doradial;
d3041 9
d3051 6
a3056 3
  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d3059 14
a3072 3
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;
d3074 9
a3082 1
    fp = strpbrk(keyp->field, ".") + 1;
a3083 4
    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        idis = 0;
d3085 2
a3086 1
        idis = ncoeff[0];
d3089 6
a3094 2
      sscanf(fp+4, "%d", &k);
      dis->dparm[j][idis+k] = wcsutil_dpkey_double(keyp);
d3096 2
d3116 1
a3116 1
  if (i[3] != 4 || 2 < Nhat) {
d3120 10
a3129 1
  if (inverse) p += i[3];
d3131 1
a3131 1
  u = rawcrd[0];
a3137 2
  v = rawcrd[1];

d3140 2
a3141 1
  if (i[4]) {
d3164 1
a3164 1
  if (i[3] != 7 || 2 < Nhat) {
d3168 10
a3177 1
  if (inverse) p += i[3];
d3179 1
a3179 1
  u = rawcrd[0];
a3185 2
  v = rawcrd[1];

d3190 2
a3191 1
  if (i[4]) {
d3214 1
a3214 1
  if (i[3] != 12 || 2 < Nhat) {
d3218 10
a3227 1
  if (inverse) p += i[3];
d3229 1
a3229 1
  u = rawcrd[0];
a3235 2
  v = rawcrd[1];

d3241 2
a3242 1
  if (i[4]) {
d3265 1
a3265 1
  if (i[3] != 17 || 2 < Nhat) {
d3269 10
a3278 1
  if (inverse) p += i[3];
d3280 1
a3280 1
  u = rawcrd[0];
a3286 2
  v = rawcrd[1];

d3293 2
a3294 1
  if (i[4]) {
d3317 1
a3317 1
  if (i[3] != 24 || 2 < Nhat) {
d3321 10
a3330 1
  if (inverse) p += i[3];
d3332 1
a3332 1
  u = rawcrd[0];
a3338 2
  v = rawcrd[1];

d3346 2
a3347 1
  if (i[4]) {
d3370 1
a3370 1
  if (i[3] != 31 || 2 < Nhat) {
d3374 10
a3383 1
  if (inverse) p += i[3];
d3385 1
a3385 1
  u = rawcrd[0];
a3391 2
  v = rawcrd[1];

d3400 2
a3401 1
  if (i[4]) {
d3424 1
a3424 1
  if (i[3] != 40 || 2 < Nhat) {
d3428 10
a3437 1
  if (inverse) p += i[3];
d3439 1
a3439 1
  u = rawcrd[0];
a3445 2
  v = rawcrd[1];

d3455 2
a3456 1
  if (i[4]) {
d3479 1
a3479 1
  if (i[3] != 49 || 2 < Nhat) {
d3483 10
a3492 1
  if (inverse) p += i[3];
d3494 1
a3494 1
  u = rawcrd[0];
a3500 2
  v = rawcrd[1];

d3511 2
a3512 1
  if (i[4]) {
d3535 1
a3535 1
  if (i[3] != 60 || 2 < Nhat) {
d3539 10
a3548 1
  if (inverse) p += i[3];
d3550 1
a3550 1
  u = rawcrd[0];
a3556 2
  v = rawcrd[1];

d3568 2
a3569 1
  if (i[4]) {
@


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


5.7.1.2
log
@Added (optional) auxiliary variables to TPD, and a stub for dssset().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.7.1.1 2015/06/29 02:47:24 mcalabre Exp mcalabre $
a874 7
    } else if (strcmp(dis->dtype[j], "DSS") == 0) {
      /* Digitized Sky Survey (DSS). */
      if ((status = dssset(j, dis))) {
        /* (Preserve the error message set by dssset().) */
        return status;
      }

a1705 1
  ndparm = 0;
d1739 1
a1739 1
  niparm = 6;
a1749 3
  /* No auxiliary variables yet. */
  tpd_iparm[4] = 0;

d1751 1
a1751 1
  tpd_iparm[5] = K;
d2019 1
a2019 1
  niparm = 6;
a2029 3
  /* TPV never needs auxiliary variables. */
  dis->iparm[j][4] = 0;

d2031 1
a2031 1
  dis->iparm[j][5] = doradial;
d2178 1
a2178 1
  niparm = 6;
d2190 1
a2190 1
  /* SIP never needs auxiliary variables. */
a2192 3
  /* SIP never needs the radial terms. */
  dis->iparm[j][5] = 0;

a2241 12
int dssset(int j, struct disprm *dis)

{
  static const char *function = "dssset";

  /* >>> */

  return 0;
}

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

d2370 1
a2370 1
  niparm = 6;
a2381 3
  /* Flag for presence of auxiliary variables. */
  dis->iparm[j][4] = 0;

d2383 1
a2383 1
  dis->iparm[j][5] = doradial;
d2430 2
a2432 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2439 2
d2443 1
a2443 2
  /* Radial terms? */
  if (i[5]) {
d2470 2
a2472 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2479 2
d2485 1
a2485 2
  /* Radial terms? */
  if (i[5]) {
d2512 2
a2514 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2521 2
d2528 1
a2528 2
  /* Radial terms? */
  if (i[5]) {
d2555 2
a2557 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2564 2
d2572 1
a2572 2
  /* Radial terms? */
  if (i[5]) {
d2599 2
a2601 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2608 2
d2617 1
a2617 2
  /* Radial terms? */
  if (i[5]) {
d2644 2
a2646 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2653 2
d2663 1
a2663 2
  /* Radial terms? */
  if (i[5]) {
d2690 2
a2692 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2699 2
d2710 1
a2710 2
  /* Radial terms? */
  if (i[5]) {
d2737 2
a2739 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2746 2
d2758 1
a2758 2
  /* Radial terms? */
  if (i[5]) {
d2785 2
a2787 11
  v = rawcrd[1];

  /* Auxiliary variables? */
  if (i[4]) {
    r = p[0] + p[1]*u + p[2]*v;
    v = p[3] + p[4]*u + p[5]*v;
    u = r;
    p += 6;
  }

  if (inverse) p += i[3];
d2794 2
d2807 1
a2807 2
  /* Radial terms? */
  if (i[5]) {
@


5.7.1.3
log
@Wrote dssset().  Take care of auxiliary variables in tpdset().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.7.1.2 2015/07/03 05:42:33 mcalabre Exp mcalabre $
d40 1
a41 1
const int POLYNOMIAL = 2;
a1945 2

  /* Initialize. */
a1948 1
  /* TPV "projection". */
d1952 1
a2093 2

  /* Initialize. */
a2096 1
  /* Simple Imaging Polynomial. */
d2100 1
d2264 1
a2264 184
  char   *fp, id[16];
  int    degree, idp, m, ncoeff, ndparm, niparm;
  double A1, A2, A3, B1, B2, B3, coeff, *dparm, S, X0, Y0;
  struct dpkey *keyp;
  struct wcserr **err;


  /* Initialize. */
  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  /* Digitized Sky Survey. */
  sprintf(id, "DSS on axis %d", j+1);


  if (dis->Nhat[j] != 2) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
  }

  /* Safe to assume the polynomial is degree is 5 (or less). */
  ncoeff = 24;
  dis->disp2x[j] = tpd5;


 /* Record indexing parameters. */
  niparm = 6;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* The first three are required by disprt(). */
  ndparm = 6 + ncoeff;
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff;

  /* DSS always needs auxiliary variables. */
  dis->iparm[j][4] = 1;

  /* DSS never needs the radial terms. */
  dis->iparm[j][5] = 0;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* This translation follows WCS Paper IV, Sect. 5.2 using the same */
  /* variable names.  Find A1, A2, A3, B1, B2, and B3.               */
  A1 = A2 = A3 = 0.0;
  B1 = B2 = B3 = 0.0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    fp = strpbrk(keyp->field, ".") + 1;
    if (strncmp(fp, "AMD.", 4) == 0) {
      fp += 4;
      sscanf(fp, "%d", &m);

      if (m == 1) {
        if (keyp->j == 1) {
          A1 = wcsutil_dpkey_double(keyp);
        } else {
          B1 = wcsutil_dpkey_double(keyp);
        }
      } else if (m == 2) {
        if (keyp->j == 1) {
          A2 = wcsutil_dpkey_double(keyp);
        } else {
          B2 = wcsutil_dpkey_double(keyp);
        }
      } else if (m == 3) {
        if (keyp->j == 1) {
          A3 = wcsutil_dpkey_double(keyp);
        } else {
          B3 = wcsutil_dpkey_double(keyp);
        }
      }
    }
  }

  X0 = (A2*B3 - A3*B1) / (A1*B1 - A2*B2);
  Y0 = (A3*B2 - A1*B3) / (A1*B1 - A2*B2);

  S = sqrt(fabs(A1*B1 - A2*B2));
  if (S == 0.0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Coefficient scale for %s is zero.", id);
  }

  /* Coefficients for the auxiliary variables. */
  dparm = dis->dparm[j];
  if (j == 0) {
    dparm[0] =  X0;
    dparm[1] = -B1/S;
    dparm[2] = -A2/S;
    dparm[3] =  Y0;
    dparm[4] =  B2/S;
    dparm[5] =  A1/S;

    /* Change the sign of S for scaling the A coefficients. */
    S *= -1.0;

  } else {
    dparm[0] =  Y0;
    dparm[1] =  B2/S;
    dparm[2] =  A1/S;
    dparm[3] =  X0;
    dparm[4] = -B1/S;
    dparm[5] = -A2/S;
  }

  /* Translate DSS coefficients to TPD. */
  dparm += 6;
  degree = 3;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "AMD.", 4) == 0) {
      /* Skip zero coefficients. */
      if ((coeff = wcsutil_dpkey_double(keyp)) == 0.0) continue;

      fp += 4;
      sscanf(fp, "%d", &m);

      /* Apply the coefficient scale factor. */
      coeff /= S;

      if (m == 1) {
        dparm[1]  = coeff;
      } else if (m == 2) {
        dparm[2]  = coeff;
      } else if (m == 3) {
        dparm[0]  = coeff;
      } else if (m == 4) {
        dparm[4] += coeff;
      } else if (m == 5) {
        dparm[5]  = coeff;
      } else if (m == 6) {
        dparm[6] += coeff;
      } else if (m == 7) {
        dparm[4] += coeff;
        dparm[6] += coeff;
      } else if (m == 8) {
        dparm[7] += coeff;
      } else if (m == 9) {
        dparm[8]  = coeff;
      } else if (m == 10) {
        dparm[9] += coeff;
      } else if (m == 11) {
        dparm[10] = coeff;
      } else if (m == 12) {
        dparm[7] += coeff;
        dparm[9] += coeff;
      } else if (m == 13) {
        dparm[17] = coeff;
        dparm[19] = coeff * 2.0;
        dparm[21] = coeff;
	degree = 5;
      } else if (coeff != 0.0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid parameter for %s: %s", m, id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  /* The DSS polynomial doesn't have 4th degree terms, and the 5th degree
     coefficient is often zero. */
  if (degree == 3) {
    dis->iparm[j][3] = 12;
    dis->disp2x[j] = tpd3;
  }
d2277 1
a2277 1
  int    doaux, doradial, idis, idp, k, m, ncoeff[2], ndparm, niparm;
a2297 1
  doaux     = 0;
a2332 4
    } else if (strncmp(fp, "AUX.", 4) == 0) {
      /* Flag usage of auxiliary variables. */
      doaux = 1;

d2405 1
a2405 1
  ndparm = (doaux?6:0) + ncoeff[0] + ncoeff[1];
d2412 1
a2412 1
  dis->iparm[j][4] = doaux;
a2422 6
  /* Set default auxiliary coefficients. */
  if (doaux) {
    dis->dparm[j][1] = 1.0;
    dis->dparm[j][5] = 1.0;
  }

d2429 1
a2429 2
    if (strncmp(fp, "AUX.", 4) == 0) {
      /* Auxiliary variables. */
d2431 4
a2434 32
      sscanf(fp, "%d", &k);
      if (k < 1 || 2 < k) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
      }

      if ((fp = strpbrk(fp, ".")) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      if (strncmp(fp, "COEFF.", 6) != 0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 6;
      sscanf(fp, "%d", &m);
      if (m < 0 || 2 < m) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid coefficient number (%d) for %s: %s", m, id, keyp->field);
      }

      idis = 3*(k-1) + m;
      dis->dparm[j][idis] = wcsutil_dpkey_double(keyp);

    } else if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      idis = (doaux?6:0);
      if (strncmp(fp, "REV.", 4) == 0) {
        idis += ncoeff[0];
@


5.7.1.4
log
@New function dishdo().  Renamed TPD -> DIS_TPD, and POLYNOMIAL ->
DIS_POLYNOMIAL, and added DIS_DOTPD.  Revised dis_errmsg[] for
DISERR_BAD_PARAM.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.7.1.3 2015/07/03 13:26:54 mcalabre Exp mcalabre $
d40 2
a41 3
const int DIS_TPD        =    1;
const int DIS_POLYNOMIAL =    2;
const int DIS_DOTPD      = 1024;
d51 1
a51 1
  "Invalid parameter value",
a547 33
int dishdo(struct disprm *dis)

{
  static const char *function = "dishdo";

  int j, status;
  struct wcserr **err;

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  status = 0;
  for (j = 0; j < dis->naxis; j++) {
    if (dis->iparm[j][0]) {
      if (dis->iparm[j][0] == DIS_TPD) {
        /* Implemented as TPD... */
        if (strcmp(dis->dtype[j], "TPD") != 0) {
          /* ... but isn't TPD. */
          dis->iparm[j][0] |= DIS_DOTPD;
        }
      } else {
        /* Must be a Polynomial that can't be implemented as TPD. */
        status = wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Translation of %s to TPD is not possible", dis->dtype[j]);
      }
    }
  }

  return status;
}

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

d1405 1
a1405 1
  iparm[I_DTYPE]  = DIS_POLYNOMIAL;
d1753 1
a1753 1
  tpd_iparm[0] = DIS_TPD;
d2038 1
a2038 1
  dis->iparm[j][0] = DIS_TPD;
d2203 1
a2203 1
  dis->iparm[j][0] = DIS_TPD;
d2301 1
a2301 1
  dis->iparm[j][0] = DIS_TPD;
d2598 1
a2598 1
  dis->iparm[j][0] = DIS_TPD;
@


5.7.1.5
log
@Handle WAT (TNX & ZPX) distortions, new functions watset() and cheleg().
Added hooks (DOCORR) for the distortion function to be applied as a
correction.  In dpfill(), fill the axis number in the keyword from the value
of j given if non-zero.  Always use preprocessor macros for indexing iparm,
including for TPD.  Replace use of strpbrk() with strchr() wherever possible.
Function prototypes for internal helper functions moved here from dis.h.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.7.1.4 2015/07/05 08:18:09 mcalabre Exp mcalabre $
a58 29
/* Internal helper functions, not for general use. */
static int polyset(int j, struct disprm *dis);
static int tpdset(int j, struct disprm *dis);

static int pol2tpd(int j, struct disprm *dis);
static int tpvset(int j, struct disprm *dis);
static int sipset(int j, struct disprm *dis);
static int dssset(int j, struct disprm *dis);
static int watset(int j, struct disprm *dis);
static int cheleg(int type, int m, int n, double coeffm[], double coeffn[]);

static int dispoly(DISP2X_ARGS);
static int tpd1(DISP2X_ARGS);
static int tpd2(DISP2X_ARGS);
static int tpd3(DISP2X_ARGS);
static int tpd4(DISP2X_ARGS);
static int tpd5(DISP2X_ARGS);
static int tpd6(DISP2X_ARGS);
static int tpd7(DISP2X_ARGS);
static int tpd8(DISP2X_ARGS);
static int tpd9(DISP2X_ARGS);

/* The first four iparm indices have meanings common to all distortion      */
/* functions.  They are used by disp2x(), disx2p(), disprt(), and dishdo(). */
#define I_DTYPE   0	/* Distortion type code.                            */
#define I_NIPARM  1	/* Full (allocated) length of iparm[].              */
#define I_NDPARM  2	/* No. of parameters in dparm[], excl. work space.  */
#define I_DOCORR  3	/* True if distortion func computes a correction.   */

d75 1
a75 1
  char axno[8], *cp;
d79 1
a79 14
      if (j && 2 <= strlen(keyword)) {
        /* Fill in the axis number from the value given. */
        if (keyword[2] == '\0') {
          sprintf(dp->field, "%s%d.%s", keyword, j, field);
        } else {
          /* Take care not to overwrite any alternate code. */
          sprintf(dp->field, "%s.%s", keyword, field);
          sprintf(axno, "%d", j);
          dp->field[2] = axno[0];
        }

      } else {
        sprintf(dp->field, "%s.%s", keyword, field);
      }
d445 1
a445 1
      for (k = 0; k < dis->iparm[j][I_NIPARM]; k++) {
d462 1
a462 1
      for (k = 0; k < dis->iparm[j][I_NDPARM]; k++) {
d562 2
a563 2
    if (dis->iparm[j][I_DTYPE]) {
      if (dis->iparm[j][I_DTYPE] == DIS_TPD) {
d567 1
a567 1
          dis->iparm[j][I_DTYPE] |= DIS_DOTPD;
d774 1
a774 1
    if ((fp = strchr(keyp->field, '.')) == 0x0) {
a809 3

    /* DOCORR should also be handled here but no space was provided for it
       in disprm. */
a915 7
    } else if (strncmp(dis->dtype[j], "WAT", 3) == 0) {
      /* WAT (TNX or ZPX "projections"). */
      if ((status = watset(j, dis))) {
        /* (Preserve the error message set by watset().) */
        return status;
      }

d982 1
a982 6
      if (dis->iparm[j][I_DOCORR]) {
        /* Distortion function computes a correction. */
        discrd[j] = rawcrd[j] + dtmp;
      } else {
        discrd[j] = dtmp;
      }
d1065 1
a1065 6
      if (dis->iparm[j][I_DOCORR]) {
        /* Inverse distortion function computes a correction. */
        rawcrd[j] = discrd[j] + rtmp;
      } else {
        rawcrd[j] = rtmp;
      }
d1369 1
a1369 1
    if ((fp = strchr(keyp->field, '.')) == 0x0) {
d1398 19
a1416 17
/* These iparm indices are specific to Polynomial.                          */
#define I_NIDX    4	/* No. of indexes in iparm[].                       */
#define I_LENDP   5	/* Full (allocated) length of dparm[].              */
#define I_K       6	/* No. of auxiliary variables.                      */
#define I_M       7	/* No. of terms in the polynomial.                  */
#define I_NKPARM  8	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  9	/* No. of parameters used to define each term.      */
#define I_NVAR   10	/* No. of independent + auxiliary variables.        */
#define I_MNVAR  11	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  12	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   13	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  14	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 15	/* iparm offset for max powers.                     */
#define I_DPOFF  16	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  17	/* iparm offset for flags.                          */
#define I_IPOW   18	/* iparm offset for integral powers.                */
#define I_NPOLY  19
d1418 2
a1419 2
  /* Add extra for handling integer exponents.  See "Optimization" below. */
  niparm = I_NPOLY + (2 + 2*M)*nVar;
d1438 1
a1438 1
  /* Record the indexing parameters.  The first four are more widely used. */
d1442 1
a1442 3
  iparm[I_DOCORR] = 0;

  iparm[I_NIDX]   = I_NPOLY;
d1481 1
a1481 1
    fp = strchr(keyp->field, '.') + 1;
d1483 1
a1483 6
    if (strncmp(fp, "DOCORR:", 7) == 0) {
      fp += 7;
      sscanf(fp, "%d", &k);
      if (k) iparm[I_DOCORR] = 1;

    } else if (strncmp(fp, "AUX.", 4) == 0) {
d1492 1
a1492 1
      if ((fp = strchr(fp, '.')) == 0x0) {
d1529 1
a1529 1
      if ((fp = strchr(fp, '.')) == 0x0) {
d1585 1
a1585 1
  /*  I_NPOLY indexing parameters, as above,                                */
a1659 233
int tpdset(int j, struct disprm *dis)

{
  static const char *function = "tpdset";

  char   *fp, id[16];
  int    doaux, docorr, doradial, idis, idp, k, m, ncoeff[2], ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  sprintf(id, "TPD on axis %d", j+1);


  /* TPD distortion. */
  if (dis->Nhat[j] < 1 || 2 < dis->Nhat[j]) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 1 or 2 entries, not %d", id,
      dis->Nhat[j]);
  }

  /* Find the number of parameters. */
  ncoeff[0] = 0;
  ncoeff[1] = 0;
  doaux     = 0;
  doradial  = 0;
  docorr    = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        idis = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        /* TPD may provide a polynomial approximation for the inverse. */
        idis = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 59) {
        if (ncoeff[idis] < k+1) ncoeff[idis] = k+1;

        /* Any radial terms? */
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }

    } else if (strncmp(fp, "AUX.", 4) == 0) {
      /* Flag usage of auxiliary variables. */
      doaux = 1;

    } else if (strncmp(fp, "DOCORR:", 7) == 0) {
      fp += 7;
      sscanf(fp, "%d", &k);
      if (k) docorr = 1;


    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (idis = 0; idis < 2; idis++) {
    if (ncoeff[idis] <= 4) {
      if (idis) {
        /* No inverse polynomial. */
        break;
      }

      /* First degree. */
      ncoeff[idis] = 4;
      distpd[idis] = tpd1;
    } else if (ncoeff[idis] <= 7) {
      /* Second degree. */
      ncoeff[idis] = 7;
      distpd[idis] = tpd2;
    } else if (ncoeff[idis] <= 12) {
      /* Third degree. */
      ncoeff[idis] = 12;
      distpd[idis] = tpd3;
    } else if (ncoeff[idis] <= 17) {
      /* Fourth degree. */
      ncoeff[idis] = 17;
      distpd[idis] = tpd4;
    } else if (ncoeff[idis] <= 24) {
      /* Fifth degree. */
      ncoeff[idis] = 24;
      distpd[idis] = tpd5;
    } else if (ncoeff[idis] <= 31) {
      /* Sixth degree. */
      ncoeff[idis] = 31;
      distpd[idis] = tpd6;
    } else if (ncoeff[idis] <= 40) {
      /* Seventh degree. */
      ncoeff[idis] = 40;
      distpd[idis] = tpd7;
    } else if (ncoeff[idis] <= 49) {
      /* Eighth degree. */
      ncoeff[idis] = 49;
      distpd[idis] = tpd8;
    } else if (ncoeff[idis] <= 60) {
      /* Ninth degree. */
      ncoeff[idis] = 60;
      distpd[idis] = tpd9;
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid number of parameters (%d) for %s", ncoeff[idis], id);
    }
  }

  /* disx2p() only uses the inverse TPD, if present, to provide a better */
  /* zeroth approximation. */
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


/* These iparm indices are specific to TPD.                      */
#define I_TPDNCO  4	/* No. of TPD coefficients.              */
#define I_TPDAUX  5	/* True if auxiliary variables are used. */
#define I_TPDRAD  6	/* True if the radial variable is used.  */
#define I_NTPD    7

  /* Record indexing parameters. */
  niparm = I_NTPD;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  ndparm = (doaux?6:0) + ncoeff[0] + ncoeff[1];

  /* The first four are more widely used. */
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;
  dis->iparm[j][I_DOCORR] = docorr;

  /* Number of TPD coefficients. */
  dis->iparm[j][I_TPDNCO] = ncoeff[0];

  /* Flag for presence of auxiliary variables. */
  dis->iparm[j][I_TPDAUX] = doaux;

  /* Flag for presence of radial terms. */
  dis->iparm[j][I_TPDRAD] = doradial;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* Set default auxiliary coefficients. */
  if (doaux) {
    dis->dparm[j][1] = 1.0;
    dis->dparm[j][5] = 1.0;
  }

  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strchr(keyp->field, '.') + 1;

    if (strncmp(fp, "AUX.", 4) == 0) {
      /* Auxiliary variables. */
      fp += 4;
      sscanf(fp, "%d", &k);
      if (k < 1 || 2 < k) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
      }

      if ((fp = strchr(fp, '.')) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      if (strncmp(fp, "COEFF.", 6) != 0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 6;
      sscanf(fp, "%d", &m);
      if (m < 0 || 2 < m) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid coefficient number (%d) for %s: %s", m, id, keyp->field);
      }

      idis = 3*(k-1) + m;
      dis->dparm[j][idis] = wcsutil_dpkey_double(keyp);

    } else if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      idis = (doaux?6:0);
      if (strncmp(fp, "REV.", 4) == 0) {
        idis += ncoeff[0];
      }

      sscanf(fp+4, "%d", &k);
      dis->dparm[j][idis+k] = wcsutil_dpkey_double(keyp);
    }
  }

  return 0;
}

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

d1781 1
a1781 1
  niparm = I_NTPD;
d1786 5
a1790 8
  /* The first four are more widely used. */
  tpd_iparm[I_DTYPE]  = DIS_TPD;
  tpd_iparm[I_NIPARM] = niparm;
  tpd_iparm[I_NDPARM] = ndparm;
  tpd_iparm[I_DOCORR] = iparm[I_DOCORR];

  /* Number of TPD coefficients. */
  tpd_iparm[I_TPDNCO] = ndparm;
d1793 1
a1793 1
  tpd_iparm[I_TPDAUX] = 0;
d1796 1
a1796 1
  tpd_iparm[I_TPDRAD] = K;
d1855 7
a1861 1
int tpvset(int j, struct disprm *dis)
d1864 110
a1973 1
  static const char *function = "tpvset";
d2001 1
a2001 1
    fp = strchr(keyp->field, '.') + 1;
d2066 1
a2066 1
  niparm = I_NTPD;
d2071 5
a2075 8
  /* The first four are more widely used. */
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;
  dis->iparm[j][I_DOCORR] = 0;

  /* Number of TPD coefficients. */
  dis->iparm[j][I_TPDNCO] = ndparm;
d2078 1
a2078 1
  dis->iparm[j][I_TPDAUX] = 0;
d2081 1
a2081 1
  dis->iparm[j][I_TPDRAD] = doradial;
d2093 1
a2093 1
    fp = strchr(keyp->field, '.') + 1;
d2151 1
a2151 1
    fp = strchr(keyp->field, '.') + 1;
d2230 1
a2230 1
  niparm = I_NTPD;
d2235 1
d2237 4
a2240 9

  /* The first four are more widely used. */
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;
  dis->iparm[j][I_DOCORR] = 0;

  /* Number of TPD coefficients. */
  dis->iparm[j][I_TPDNCO] = ncoeff[0];
d2243 1
a2243 1
  dis->iparm[j][I_TPDAUX] = 0;
d2246 1
a2246 1
  dis->iparm[j][I_TPDRAD] = 0;
d2258 1
a2258 1
    fp = strchr(keyp->field, '.') + 1;
d2284 1
a2284 1
  dis->dparm[j][0] = dis->offset[j][jhat];
d2322 1
a2322 1
  /* Safe to assume the polynomial degree is 5 (or less). */
d2328 1
a2328 1
  niparm = I_NTPD;
d2333 1
d2335 4
a2338 9

  /* The first four are more widely used. */
  dis->iparm[j][I_DTYPE]  = DIS_TPD;
  dis->iparm[j][I_NIPARM] = niparm;
  dis->iparm[j][I_NDPARM] = ndparm;
  dis->iparm[j][I_DOCORR] = 0;

  /* Number of TPD coefficients. */
  dis->iparm[j][I_TPDNCO] = ncoeff;
d2341 1
a2341 1
  dis->iparm[j][I_TPDAUX] = 1;
d2344 1
a2344 1
  dis->iparm[j][I_TPDRAD] = 0;
d2358 3
a2360 3
    fp = strchr(keyp->field, '.') + 1;
    if (strncmp(fp, "DSS.AMD.", 8) == 0) {
      fp += 8;
d2423 1
a2423 1
    fp = strchr(keyp->field, '.') + 1;
d2425 1
a2425 1
    if (strncmp(fp, "DSS.AMD.", 8) == 0) {
d2429 1
a2429 1
      fp += 8;
d2483 1
a2483 1
    dis->iparm[j][I_TPDNCO] = 12;
d2492 1
a2492 5
#define CHEBYSHEV 1
#define LEGENDRE  2
#define MONOMIAL  3

int watset(int j, struct disprm *dis)
d2495 1
a2495 12
  static const char *function = "watset";

  static const int map[][10] = {{ 0,  2,  6, 10, 16, 22, 30, 38, 48, 58},
                                { 1,  5,  9, 15, 21, 29, 37, 47, 57, -1},
                                { 4,  8, 14, 20, 28, 36, 46, 56, -1, -1},
                                { 7, 13, 19, 27, 35, 45, 55, -1, -1, -1},
                                {12, 18, 26, 34, 44, 54, -1, -1, -1, -1},
                                {17, 25, 33, 43, 53, -1, -1, -1, -1, -1},
                                {24, 32, 42, 52, -1, -1, -1, -1, -1, -1},
                                {31, 41, 51, -1, -1, -1, -1, -1, -1, -1},
                                {40, 50, -1, -1, -1, -1, -1, -1, -1, -1},
                                {49, -1, -1, -1, -1, -1, -1, -1, -1, -1}};
d2498 1
a2498 4
  int    deg, degree, doaux, idis, idp, im, in, *iparm, kind, m, n, ncoeff,
         ndparm, niparm;
  double coeff, coeffm[10], coeffn[10], *dparm, dx, dy, x0, xmax, xmin,
         y0, ymax, ymin;
d2501 1
a2502 2

  /* Initialize. */
d2506 2
a2507 2
  /* WAT (TNX or ZPX) Polynomial. */
  sprintf(id, "WAT (%s) on axis %d", dis->dtype[0]+4, j+1);
d2509 2
a2510 1
  if (dis->Nhat[j] != 2) {
d2512 2
a2513 1
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
d2516 5
a2520 5
  /* Find the polynomial degree (at least 1), kind, and domain. */
  degree = 1;
  kind = 0;
  xmin = xmax = 0.0;
  ymin = ymax = 0.0;
d2525 1
a2525 1
    fp = strchr(keyp->field, '.') + 1;
d2527 1
a2527 1
    if (strncmp(fp, "WAT.", 4) == 0) {
d2529 2
a2530 11
      if (strncmp(fp, "CHBY.", 5) == 0 ||
          strncmp(fp, "LEGR.", 5) == 0 ||
          strncmp(fp, "MONO.", 5) == 0) {

        fp += 5;
        sscanf(fp, "%d_%d", &m, &n);
        deg = m + n;
        if (m < 0 || 9 < m || n < 0 || 9 < n || 9 < deg) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid powers (%d, %d) for %s: %s", m, n, id, keyp->field);
        }
d2532 3
a2534 1
        if (degree < deg) degree = deg;
d2536 4
a2539 2
      } else if (strcmp(fp, "POLY") == 0) {
        kind = wcsutil_dpkey_int(keyp);
d2541 3
a2543 2
      } else if (strcmp(fp, "XMIN") == 0) {
        xmin = wcsutil_dpkey_double(keyp);
d2545 4
a2548 2
      } else if (strcmp(fp, "XMAX") == 0) {
        xmax = wcsutil_dpkey_double(keyp);
d2550 4
a2553 2
      } else if (strcmp(fp, "YMIN") == 0) {
        ymin = wcsutil_dpkey_double(keyp);
d2555 3
a2557 3
      } else if (strcmp(fp, "YMAX") == 0) {
        ymax = wcsutil_dpkey_double(keyp);
      }
d2568 8
a2575 1
  doaux = (kind == 1 || kind == 2);
d2577 39
a2615 38
  /* TPD is going to do the dirty work. */
  ncoeff = 0;
  if (degree == 1) {
    /* First degree. */
    ncoeff = 4;
    dis->disp2x[j] = tpd1;
  } else if (degree == 2) {
    /* Second degree. */
    ncoeff = 7;
    dis->disp2x[j] = tpd2;
  } else if (degree == 3) {
    /* Third degree. */
    ncoeff = 12;
    dis->disp2x[j] = tpd3;
  } else if (degree == 4) {
    /* Fourth degree. */
    ncoeff = 17;
    dis->disp2x[j] = tpd4;
  } else if (degree == 5) {
    /* Fifth degree. */
    ncoeff = 24;
    dis->disp2x[j] = tpd5;
  } else if (degree == 6) {
    /* Sixth degree. */
    ncoeff = 31;
    dis->disp2x[j] = tpd6;
  } else if (degree == 7) {
    /* Seventh degree. */
    ncoeff = 40;
    dis->disp2x[j] = tpd7;
  } else if (degree == 8) {
    /* Eighth degree. */
    ncoeff = 49;
    dis->disp2x[j] = tpd8;
  } else if (degree == 9) {
    /* Ninth degree. */
    ncoeff = 60;
    dis->disp2x[j] = tpd9;
d2618 4
a2621 2
  /* No specialist de-distortions. */
  dis->disx2p[j] = 0x0;
d2625 1
a2625 1
  niparm = I_NTPD;
d2630 6
a2635 1
  iparm = dis->iparm[j];
d2637 2
a2638 1
  ndparm = 6 + ncoeff;
d2640 2
a2641 14
  /* The first four are more widely used. */
  iparm[I_DTYPE]  = DIS_TPD;
  iparm[I_NIPARM] = niparm;
  iparm[I_NDPARM] = ndparm;
  iparm[I_DOCORR] = 1;

  /* Number of TPD coefficients. */
  iparm[I_TPDNCO] = ncoeff;

  /* The Chebyshev and Legendre polynomials use auxiliary variables. */
  iparm[I_TPDAUX] = doaux;

  /* WAT never needs the radial terms. */
  iparm[I_TPDRAD] = 0;
d2649 1
a2649 4
  dparm = dis->dparm[j];


  /* Coefficients for the auxiliary variables. */
d2651 2
a2652 23
    x0 = (xmax + xmin)/2.0;
    dx = (xmax - xmin)/2.0;
    if (dx == 0.0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "X-span for %s is zero", id);
    }

    dparm[0] = -x0/dx;
    dparm[1] = 1.0/dx;
    dparm[2] = 0.0;

    y0 = (ymax + ymin)/2.0;
    dy = (ymax - ymin)/2.0;
    if (dy == 0.0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Y-span for %s is zero", id);
    }

    dparm[3] = -y0/dy;
    dparm[4] = 0.0;
    dparm[5] = 1.0/dy;

    dparm += 6;
a2654 2

  /* Unpack the polynomial coefficients. */
d2659 1
a2659 1
    fp = strchr(keyp->field, '.') + 1;
d2661 8
a2668 11
    if ((kind == CHEBYSHEV && strncmp(fp, "WAT.CHBY.", 9) == 0) ||
        (kind == LEGENDRE  && strncmp(fp, "WAT.LEGR.", 9) == 0) ||
        (kind == MONOMIAL  && strncmp(fp, "WAT.MONO.", 9) == 0)) {
      fp += 9;

      sscanf(fp, "%d_%d", &m, &n);

      if (kind == MONOMIAL) {
        /* Monomial coefficient, maps simply to TPD coefficient number. */
        idis = map[m][n];
        dparm[idis] = wcsutil_dpkey_double(keyp);
d2670 5
a2674 8
      } else {
        /* Coefficient of the product of two Chebyshev or two Legendre */
        /* polynomials.  Find the corresponding monomial coefficients. */
        coeff = wcsutil_dpkey_double(keyp);

        cheleg(kind, m, n, coeffm, coeffn);
        for (im = 0; im <= m; im++) {
          if (coeffm[im] == 0.0) continue;
d2676 3
a2678 7
          for (in = 0; in <= n; in++) {
            if (coeffn[in] == 0.0) continue;

            idis = map[im][in];
            dparm[idis] += coeff*coeffm[im]*coeffn[in];
          }
        }
a2679 2
    }
  }
d2681 5
a2685 45
  return 0;
}

/*--------------------------------------------------------------------------*/
/* Compute the coefficients of Chebyshev or Legendre polynomials of degree  */
/* m and n.                                                                 */

int cheleg(int kind, int m, int n, double coeffm[], double coeffn[])

{
  int    j, j0, j1, j2, k, N;
  double *coeff[3], d;

  N = (m > n) ? m : n;

  /* Allocate work arrays. */
  coeff[0] = calloc(3*(N+1), sizeof(double));
  coeff[1] = coeff[0] + (N+1);
  coeff[2] = coeff[1] + (N+1);

  for (j = 0; j <= N; j++) {
    j0 =  j%3;

    if (j == 0) {
      coeff[0][0] = 1.0;

    } else if (j == 1) {
      coeff[1][1] = 1.0;

    } else {
      /* Cyclic buffer indices. */
      j1 = (j-1)%3;
      j2 = (j-2)%3;

      memset(coeff[j0], 0, (N+1)*sizeof(double));

      d = (double)j;
      for (k = 0; k < N; k++) {
        if (kind == CHEBYSHEV) {
          coeff[j0][k+1] = 2.0 * coeff[j1][k];
          coeff[j0][k]  -=       coeff[j2][k];
        } else if (kind == LEGENDRE) {
          coeff[j0][k+1] = ((2.0*d - 1.0) * coeff[j1][k]) / d;
          coeff[j0][k]  -=     ((d - 1.0) * coeff[j2][k]) / d;
        }
a2686 1
    }
d2688 2
a2689 3
    if (j == m) memcpy(coeffm, coeff[j0], (m+1)*sizeof(double));
    if (j == n) memcpy(coeffn, coeff[j0], (n+1)*sizeof(double));
  }
d2691 5
a2695 104
  free(coeff[0]);

  return 0;
}

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

int dispoly(
  int inverse,
  const int iparm[],
  const double dparm[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  const int *iflgp, *imaxp, *imaxpow, *ipowp;
  int    ip, ivar, jhat, k, m;
  const double *cptr, *dpolp, *pptr;
  double *aux, auxp0, *dvarpow, *dpowp, term, var;

  /* Check for zeroes. */
  for (jhat = 0; jhat < Nhat; jhat++) {
    if (rawcrd[jhat] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }

  /* Working memory for auxiliaries &c. was allocated at the end of p[]. */
  aux = (double *)(dparm + iparm[I_DAUX]);

  /* Compute the auxiliary variables. */
  for (k = 0; k < iparm[I_K]; k++) {
    cptr = dparm + k*iparm[I_NKPARM];
    pptr = cptr + (1+Nhat);

    aux[k] = *(cptr++);
    auxp0  = *(pptr++);

    for (jhat = 0; jhat < Nhat; jhat++) {
      aux[k] += *(cptr++)*pow(rawcrd[jhat], *(pptr++));
    }

    aux[k] = pow(aux[k], auxp0);

    /* Check for zeroes. */
    if (aux[k] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }


  /* Compute all required integral powers of the variables. */
  imaxpow = iparm + iparm[I_MAXPOW];
  dvarpow = (double *)(dparm + iparm[I_DVPOW]);

  imaxp = imaxpow;
  dpowp = dvarpow;
  for (jhat = 0; jhat < Nhat; jhat++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= rawcrd[jhat];
      *dpowp = var;
    }
  }

  for (k = 0; k < iparm[I_K]; k++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= aux[k];
      *dpowp = var;
    }
  }

  /* Loop for each term of the polynomial. */
  *discrd = 0.0;
  iflgp = iparm + iparm[I_FLAGS];
  ipowp = iparm + iparm[I_IPOW];
  dpolp = dparm + iparm[I_DPOLY];
  for (m = 0; m < iparm[I_M]; m++) {
    term = *(dpolp++);

    /* Loop over all variables. */
    imaxp = imaxpow;
    dpowp = dvarpow - 1;
    for (ivar = 0; ivar < iparm[I_NVAR]; ivar++) {
      if (*iflgp & 2) {
        /* Nothing (zero power). */

      } else if (*iflgp) {
        /* Integral power. */
        if (*ipowp < 0) {
          /* Negative. */
          term /= dpowp[*ipowp];
        } else {
          /* Positive. */
          term *= dpowp[*ipowp];
        }

      } else {
        /* Fractional power. */
        term *= pow(dpowp[0], *dpolp);
d2698 2
a2699 6
      iflgp++;
      ipowp++;
      dpolp++;

      dpowp += *imaxp;
      imaxp++;
a2700 2

    *discrd += term;
d2719 1
a2719 1
  if (i[I_TPDNCO] != 4 || 2 < Nhat) {
d2727 1
a2727 1
  if (i[I_TPDAUX]) {
d2734 1
a2734 1
  if (inverse) p += i[I_TPDNCO];
d2744 1
a2744 1
  if (i[I_TPDRAD]) {
d2767 1
a2767 1
  if (i[I_TPDNCO] != 7 || 2 < Nhat) {
d2775 1
a2775 1
  if (i[I_TPDAUX]) {
d2782 1
a2782 1
  if (inverse) p += i[I_TPDNCO];
d2794 1
a2794 1
  if (i[I_TPDRAD]) {
d2817 1
a2817 1
  if (i[I_TPDNCO] != 12 || 2 < Nhat) {
d2825 1
a2825 1
  if (i[I_TPDAUX]) {
d2832 1
a2832 1
  if (inverse) p += i[I_TPDNCO];
d2845 1
a2845 1
  if (i[I_TPDRAD]) {
d2868 1
a2868 1
  if (i[I_TPDNCO] != 17 || 2 < Nhat) {
d2876 1
a2876 1
  if (i[I_TPDAUX]) {
d2883 1
a2883 1
  if (inverse) p += i[I_TPDNCO];
d2897 1
a2897 1
  if (i[I_TPDRAD]) {
d2920 1
a2920 1
  if (i[I_TPDNCO] != 24 || 2 < Nhat) {
d2928 1
a2928 1
  if (i[I_TPDAUX]) {
d2935 1
a2935 1
  if (inverse) p += i[I_TPDNCO];
d2950 1
a2950 1
  if (i[I_TPDRAD]) {
d2973 1
a2973 1
  if (i[I_TPDNCO] != 31 || 2 < Nhat) {
d2981 1
a2981 1
  if (i[I_TPDAUX]) {
d2988 1
a2988 1
  if (inverse) p += i[I_TPDNCO];
d3004 1
a3004 1
  if (i[I_TPDRAD]) {
d3027 1
a3027 1
  if (i[I_TPDNCO] != 40 || 2 < Nhat) {
d3035 1
a3035 1
  if (i[I_TPDAUX]) {
d3042 1
a3042 1
  if (inverse) p += i[I_TPDNCO];
d3059 1
a3059 1
  if (i[I_TPDRAD]) {
d3082 1
a3082 1
  if (i[I_TPDNCO] != 49 || 2 < Nhat) {
d3090 1
a3090 1
  if (i[I_TPDAUX]) {
d3097 1
a3097 1
  if (inverse) p += i[I_TPDNCO];
d3115 1
a3115 1
  if (i[I_TPDRAD]) {
d3138 1
a3138 1
  if (i[I_TPDNCO] != 60 || 2 < Nhat) {
d3146 1
a3146 1
  if (i[I_TPDAUX]) {
d3153 1
a3153 1
  if (inverse) p += i[I_TPDNCO];
d3172 1
a3172 1
  if (i[I_TPDRAD]) {
@


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: dis.c,v 5.5.1.2 2015/06/06 08:48:42 mcalabre Exp mcalabre $
d70 2
a71 2
  int ival,
  double fval)
d96 1
a96 1
    dp->value.f = fval;
d98 1
a98 1
    dp->value.i = ival;
a272 1
  disdst->ndpmax = dissrc->ndpmax;
d354 1
a354 1
  int i, j, k, naxis;
d402 2
a403 2
    for (i = 0; i < naxis; i++) {
      wcsprintf("%6d", dis->axmap[j][i]);
d406 2
a407 2
    for (i = naxis; i < 2*naxis; i++) {
      wcsprintf("%6d", dis->axmap[j][i]);
d422 2
a423 2
    for (i = 0; i < naxis; i++) {
      wcsprintf("  %#- 11.5g", dis->offset[j][i]);
d431 2
a432 2
    for (i = 0; i < naxis; i++) {
      wcsprintf("  %#- 11.5g", dis->scale[j][i]);
d439 10
a448 4
    wcsprintf(" iparm[%d][]:", j);
    for (k = 0; k < dis->iparm[j][1]; k++) {
      if (k && k%5 == 0) {
        wcsprintf("\n            ");
d450 1
a450 1
      wcsprintf("  %11d", dis->iparm[j][k]);
a451 1
    wcsprintf("\n");
d456 10
a465 4
    wcsprintf(" dparm[%d][]:", j);
    for (k = 0; k < dis->iparm[j][2]; k++) {
      if (k && k%5 == 0) {
        wcsprintf("\n            ");
d467 1
a467 1
      wcsprintf("  %#- 11.5g", dis->dparm[j][k]);
a468 1
    wcsprintf("\n");
d534 14
d579 1
d592 1
a592 1
        "No DPja or DQia keywords, NAXES at least is required for each"
d703 2
a704 2
  for (j = 0; j < 2*naxis*naxis; j++) {
    dis->axmap[0][j] = -1;
d710 2
a711 2
  for (j = 0; j < naxis*naxis; j++) {
    dis->scale[0][j] = 1.0;
d728 1
a728 1
    if (dis->dp[0].field[1] != dpq[1]) {
d759 1
a759 1
      if (jhat < 0 || naxis < jhat) {
d855 1
a855 1
      /* Template Polynomial Distortion". */
d907 1
a907 1
  int axisj, j, jhat, naxis, Nhat, status;
d926 3
a928 2
    offset = dis->offset[j];
    scale  = dis->scale[j];
a929 1
    if (dis->disp2x[j]) {
d952 16
a976 1
  const int ITERMAX = 30;
d979 3
a981 2
  int convergence, iter, j, jhat, naxis, Nhat, status;
  double dd, *dcrd0, *dcrd1, *delta, residual, *rcrd1, rtmp;
d1009 4
d1014 5
d1020 1
a1020 1
                                     discrd, &rtmp))) {
d1024 1
a1024 3
      /* Using the inverse axis map. */
      jhat = dis->axmap[j][naxis+j];
      rawcrd[j] = dis->offset[j][jhat] + rtmp/dis->scale[j][jhat];
d1028 5
d1035 1
a1035 1
  for (iter = 0; iter < ITERMAX; iter++) {
d1080 1
a1080 1
    if (iter < ITERMAX/2) {
d1083 1
a1083 1
      /* respect  to rawcrd[j], and we can neglect partials with respect   */
d1362 1
a1362 1
#define I_K       5	/* No. of independent variables.                    */
d1961 1
a1961 1
	/* Any radial terms? */
d2074 2
a2075 1
  int    deg, degree[2], idp, m, ncoeff[2], ndparm, niparm, p, q;
d2104 1
a2104 1
        m = 0;
d2108 1
a2108 1
        m = 1;
d2123 1
a2123 1
      if (degree[m] < deg) degree[m] = deg;
d2139 29
a2167 29
  for (m = 0; m < 2; m++) {
    ncoeff[m] = 0;
    if (degree[m] == 1) {
      ncoeff[m] = 4;
      distpd[m] = tpd1;
    } else if (degree[m] == 2) {
      ncoeff[m] = 7;
      distpd[m] = tpd2;
    } else if (degree[m] == 3) {
      ncoeff[m] = 12;
      distpd[m] = tpd3;
    } else if (degree[m] == 4) {
      ncoeff[m] = 17;
      distpd[m] = tpd4;
    } else if (degree[m] == 5) {
      ncoeff[m] = 24;
      distpd[m] = tpd5;
    } else if (degree[m] == 6) {
      ncoeff[m] = 31;
      distpd[m] = tpd6;
    } else if (degree[m] == 7) {
      ncoeff[m] = 40;
      distpd[m] = tpd7;
    } else if (degree[m] == 8) {
      ncoeff[m] = 49;
      distpd[m] = tpd8;
    } else if (degree[m] == 9) {
      ncoeff[m] = 60;
      distpd[m] = tpd9;
d2208 1
a2208 1
        m = 0;
d2210 1
a2210 1
        m = ncoeff[0];
d2216 1
a2216 1
      m += map[p][q];
d2218 1
a2218 1
      dis->dparm[j][m] = wcsutil_dpkey_double(keyp);
d2225 6
a2230 5
  /* distorted pixel coordinate.  Note also that SIP has no axis mapping, */
  /* i.e. jhat = j always.                                                */
  m = j + 1;
  dis->dparm[j][0]  = dis->offset[j][j];
  dis->dparm[j][m] += 1.0;
d2232 2
a2233 2
    dis->dparm[j][ncoeff[0]]    = dis->offset[j][j];
    dis->dparm[j][ncoeff[0]+m] += 1.0;
d2248 1
a2248 1
  int    doradial, idp, k, m, ncoeff[2], ndparm, niparm;
d2279 1
a2279 1
        m = 0;
d2283 1
a2283 1
        m = 1;
d2292 1
a2292 1
        if (ncoeff[m] < k+1) ncoeff[m] = k+1;
d2315 7
a2321 2
  for (m = 0; m < 2; m++) {
    if (ncoeff[m] <= 4) {
d2323 3
a2325 3
      ncoeff[m] = 4;
      distpd[m] = tpd1;
    } else if (ncoeff[m] <= 7) {
d2327 3
a2329 3
      ncoeff[m] = 7;
      distpd[m] = tpd2;
    } else if (ncoeff[m] <= 12) {
d2331 3
a2333 3
      ncoeff[m] = 12;
      distpd[m] = tpd3;
    } else if (ncoeff[m] <= 17) {
d2335 3
a2337 3
      ncoeff[m] = 17;
      distpd[m] = tpd4;
    } else if (ncoeff[m] <= 24) {
d2339 3
a2341 3
      ncoeff[m] = 24;
      distpd[m] = tpd5;
    } else if (ncoeff[m] <= 31) {
d2343 3
a2345 3
      ncoeff[m] = 31;
      distpd[m] = tpd6;
    } else if (ncoeff[m] <= 40) {
d2347 3
a2349 3
      ncoeff[m] = 40;
      distpd[m] = tpd7;
    } else if (ncoeff[m] <= 49) {
d2351 3
a2353 3
      ncoeff[m] = 49;
      distpd[m] = tpd8;
    } else if (ncoeff[m] <= 60) {
d2355 2
a2356 2
      ncoeff[m] = 60;
      distpd[m] = tpd9;
d2359 1
a2359 1
        "Invalid number of parameters (%d) for %s", ncoeff[m], id);
d2400 1
a2400 1
        m = 0;
d2402 1
a2402 1
        m = ncoeff[0];
d2406 1
a2406 1
      dis->dparm[j][m+k] = wcsutil_dpkey_double(keyp);
@


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


5.6.1.2
log
@In disset(), bug fix in guarding against a mix of DPja and DQia keywords,
and for validating jhat from a DPja.AXIS.jhat keyword.  In sipset(), SIP
distortions can now have a non-trivial axis map by virtue of wcssub()
prepending an axis.  In disprt(), bug fix for reporting the values of
disprm::iparm and dparm for axes without distortions.  In dpfill(), changed
variable names in the function prototype to match dpkey struct members.
In disset(), disprt() and sipset(), changed the index variable name to jhat
as appropriate for disprm::axmap, offset, and scale.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.6.1.1 2015/06/14 07:14:44 mcalabre Exp mcalabre $
d70 2
a71 2
  int i,
  double f)
d96 1
a96 1
    dp->value.f = f;
d98 1
a98 1
    dp->value.i = i;
d355 1
a355 1
  int i, j, jhat, k, naxis;
d403 2
a404 2
    for (jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("%6d", dis->axmap[j][jhat]);
d407 2
a408 2
    for (jhat = naxis; jhat < 2*naxis; jhat++) {
      wcsprintf("%6d", dis->axmap[j][jhat]);
d423 2
a424 2
    for (jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("  %#- 11.5g", dis->offset[j][jhat]);
d432 2
a433 2
    for (jhat = 0; jhat < naxis; jhat++) {
      wcsprintf("  %#- 11.5g", dis->scale[j][jhat]);
d440 4
a443 10
    wcsprintf(" iparm[%d]  : ", j);
    WCSPRINTF_PTR("", dis->iparm[j], "\n");

    if (dis->iparm[j]) {
      wcsprintf(" iparm[%d][]:", j);
      for (k = 0; k < dis->iparm[j][1]; k++) {
        if (k && k%5 == 0) {
          wcsprintf("\n            ");
        }
        wcsprintf("  %11d", dis->iparm[j][k]);
d445 1
a445 1
      wcsprintf("\n");
d447 1
d452 4
a455 10
    wcsprintf(" dparm[%d]  : ", j);
    WCSPRINTF_PTR("", dis->dparm[j], "\n");

    if (dis->dparm[j]) {
      wcsprintf(" dparm[%d][]:", j);
      for (k = 0; k < dis->iparm[j][2]; k++) {
        if (k && k%5 == 0) {
          wcsprintf("\n            ");
        }
        wcsprintf("  %#- 11.5g", dis->dparm[j][k]);
d457 1
a457 1
      wcsprintf("\n");
d459 1
a555 1
    /* Is it prior or sequent? */
d568 1
a568 1
        "No DPja or DQia keywords, NAXES at least is required for each "
d679 2
a680 2
  for (jhat = 0; jhat < 2*naxis*naxis; jhat++) {
    dis->axmap[0][jhat] = -1;
d686 2
a687 2
  for (jhat = 0; jhat < naxis*naxis; jhat++) {
    dis->scale[0][jhat] = 1.0;
d704 1
a704 1
    if (keyp->field[1] != dpq[1]) {
d735 1
a735 1
      if (jhat < 1 || naxis < jhat) {
d2022 1
a2022 1
  int    deg, degree[2], idp, jhat, m, naxis, ncoeff[2], ndparm, niparm, p, q;
d2172 4
a2175 5
  /* distorted pixel coordinate.                                          */
  naxis = dis->naxis;
  jhat  = dis->axmap[j][naxis+j];
  m = jhat + 1;
  dis->dparm[j][0]  = dis->offset[j][jhat];
d2178 1
a2178 1
    dis->dparm[j][ncoeff[0]]    = dis->offset[j][jhat];
@


5.6.1.3
log
@In discpy(), 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: dis.c,v 5.6.1.2 2015/06/16 08:08:08 mcalabre Exp mcalabre $
d273 1
@


5.6.1.4
log
@Bug fix in disx2p() concerning applying the offset and scale when invoking
disprm::disx2p.  Added disperr() and disitermax(), the latter only for
testing.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.6.1.3 2015/06/16 13:34:01 mcalabre Exp mcalabre $
a533 14
int disperr(const struct disprm *dis, const char *prefix)

{
  if (dis == 0x0) return DISERR_NULL_POINTER;

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

  return 0;
}

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

d893 1
a893 1
  int    axisj, j, jhat, naxis, Nhat, status;
d912 3
a915 3
      offset = dis->offset[j];
      scale  = dis->scale[j];

a937 16
/* This function is intended for debugging purposes only.                   */
/* No documentation or prototype is provided in dis.h.                      */

int disitermax(int itermax)

{
  static int ITERMAX = 30;

  if (itermax >= 0) {
    ITERMAX = itermax;
  }

  return ITERMAX;
}

/*--------------------------------------------------------------------------*/
d947 1
d950 2
a951 3
  int    axisj, convergence, iter, itermax, j, jhat, naxis, Nhat, status;
  double dd, *dcrd0, *dcrd1, *delta, *offset, residual, *rcrd1, rtmp, *scale,
         *tmpcrd;
a978 4
      offset = dis->offset[j];
      scale  = dis->scale[j];
      tmpcrd = dis->tmpmem;

a979 5
      for (jhat = 0; jhat < Nhat; jhat++) {
        axisj = dis->axmap[j][jhat];
        tmpcrd[jhat] = (discrd[axisj] - offset[jhat])*scale[jhat];
      }

d981 1
a981 1
                                     tmpcrd, &rtmp))) {
d985 3
a987 1
      rawcrd[j] = rtmp;
a990 5
  /* Quick return debugging hook, assumes inverse functions were defined. */
  if ((itermax = disitermax(-1)) == 0) {
    return 0;
  }

d993 1
a993 1
  for (iter = 0; iter < itermax; iter++) {
d1038 1
a1038 1
    if (iter < itermax/2) {
d1041 1
a1041 1
      /* respect to rawcrd[j], and we can neglect partials with respect    */
@


5.6.1.5
log
@In tpdset(), take care not to define an inverse distortion if no
coefficients were given.  Renamed m -> idis in sipset() and tpdset().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.6.1.4 2015/06/18 08:09:06 mcalabre Exp mcalabre $
d855 1
a855 1
      /* Template Polynomial Distortion. */
d1961 1
a1961 1
        /* Any radial terms? */
d2074 1
a2074 2
  int    deg, degree[2], idis, idp, jhat, naxis, ncoeff[2], ndparm, niparm,
         p, q;
d2103 1
a2103 1
        idis = 0;
d2107 1
a2107 1
        idis = 1;
d2122 1
a2122 1
      if (degree[idis] < deg) degree[idis] = deg;
d2138 29
a2166 29
  for (idis = 0; idis < 2; idis++) {
    ncoeff[idis] = 0;
    if (degree[idis] == 1) {
      ncoeff[idis] = 4;
      distpd[idis] = tpd1;
    } else if (degree[idis] == 2) {
      ncoeff[idis] = 7;
      distpd[idis] = tpd2;
    } else if (degree[idis] == 3) {
      ncoeff[idis] = 12;
      distpd[idis] = tpd3;
    } else if (degree[idis] == 4) {
      ncoeff[idis] = 17;
      distpd[idis] = tpd4;
    } else if (degree[idis] == 5) {
      ncoeff[idis] = 24;
      distpd[idis] = tpd5;
    } else if (degree[idis] == 6) {
      ncoeff[idis] = 31;
      distpd[idis] = tpd6;
    } else if (degree[idis] == 7) {
      ncoeff[idis] = 40;
      distpd[idis] = tpd7;
    } else if (degree[idis] == 8) {
      ncoeff[idis] = 49;
      distpd[idis] = tpd8;
    } else if (degree[idis] == 9) {
      ncoeff[idis] = 60;
      distpd[idis] = tpd9;
d2207 1
a2207 1
        idis = 0;
d2209 1
a2209 1
        idis = ncoeff[0];
d2215 1
a2215 1
      idis += map[p][q];
d2217 1
a2217 1
      dis->dparm[j][idis] = wcsutil_dpkey_double(keyp);
d2227 1
a2227 1
  idis  = jhat + 1;
d2229 1
a2229 1
  dis->dparm[j][idis] += 1.0;
d2231 2
a2232 2
    dis->dparm[j][ncoeff[0]] = dis->offset[j][jhat];
    dis->dparm[j][ncoeff[0]+idis] += 1.0;
d2247 1
a2247 1
  int    doradial, idis, idp, k, ncoeff[2], ndparm, niparm;
d2278 1
a2278 1
        idis = 0;
d2282 1
a2282 1
        idis = 1;
d2291 1
a2291 1
        if (ncoeff[idis] < k+1) ncoeff[idis] = k+1;
d2314 2
a2315 7
  for (idis = 0; idis < 2; idis++) {
    if (ncoeff[idis] <= 4) {
      if (idis) {
        /* No inverse polynomial. */
        break;
      }

d2317 3
a2319 3
      ncoeff[idis] = 4;
      distpd[idis] = tpd1;
    } else if (ncoeff[idis] <= 7) {
d2321 3
a2323 3
      ncoeff[idis] = 7;
      distpd[idis] = tpd2;
    } else if (ncoeff[idis] <= 12) {
d2325 3
a2327 3
      ncoeff[idis] = 12;
      distpd[idis] = tpd3;
    } else if (ncoeff[idis] <= 17) {
d2329 3
a2331 3
      ncoeff[idis] = 17;
      distpd[idis] = tpd4;
    } else if (ncoeff[idis] <= 24) {
d2333 3
a2335 3
      ncoeff[idis] = 24;
      distpd[idis] = tpd5;
    } else if (ncoeff[idis] <= 31) {
d2337 3
a2339 3
      ncoeff[idis] = 31;
      distpd[idis] = tpd6;
    } else if (ncoeff[idis] <= 40) {
d2341 3
a2343 3
      ncoeff[idis] = 40;
      distpd[idis] = tpd7;
    } else if (ncoeff[idis] <= 49) {
d2345 3
a2347 3
      ncoeff[idis] = 49;
      distpd[idis] = tpd8;
    } else if (ncoeff[idis] <= 60) {
d2349 2
a2350 2
      ncoeff[idis] = 60;
      distpd[idis] = tpd9;
d2353 1
a2353 1
        "Invalid number of parameters (%d) for %s", ncoeff[idis], id);
d2394 1
a2394 1
        idis = 0;
d2396 1
a2396 1
        idis = ncoeff[0];
d2400 1
a2400 1
      dis->dparm[j][idis+k] = wcsutil_dpkey_double(keyp);
@


5.6.1.6
log
@Amended the inline comment for I_K in polyset().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.6.1.5 2015/06/21 05:59:37 mcalabre Exp mcalabre $
d1362 1
a1362 1
#define I_K       5	/* No. of auxiliary variables.                      */
@


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: dis.c,v 5.4.1.3 2015/05/02 15:56:10 mcalabre Exp mcalabre $
d2169 5
a2173 3
  /* The SIP distortion is an additive correction to the pixel coordinate, */
  /* whereas we want the value of the pixel coordinate after distortion.   */
  /* Note also that SIP has no axis mapping, i.e. jhat = j always.         */
d2175 1
d2178 1
@


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


5.5.1.2
log
@In sipset(), account for the fact that the independent variables of the SIP
polynomial are pixel coordinate offsets from CRPIXja.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.5.1.1 2015/05/05 13:21:00 mcalabre Exp mcalabre $
d2169 3
a2171 5
  /* Account for the fact that the SIP distortion provides an additive    */
  /* correction to the offset of the pixel coordinate from CRPIX, whereas */
  /* we expect the distortion function to provide the actual value of the */
  /* distorted pixel coordinate.  Note also that SIP has no axis mapping, */
  /* i.e. jhat = j always.                                                */
a2172 1
  dis->dparm[j][0]  = dis->offset[j][j];
a2174 1
    dis->dparm[j][ncoeff[0]]    = dis->offset[j][j];
@


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: dis.c,v 5.3.1.2 2015/04/21 13:49:16 mcalabre Exp mcalabre $
a1870 219

/*----------------------------------------------------------------------------
* The "Template Polynomial Distortion" (TPD) is a superset of the TPV and SIP
* polynomial distortions that also supports 1D usage.  Like TPV and SIP, the
* form of the polynomial is fixed (the "template") and only the coefficients
* for the required terms are set non-zero.  TPD generalizes TPV in going to
* 9th degree, and SIP by accomodating TPV's linear and radial terms.
*
* In typical applications, TPD is considerably faster than the generalized
* Polynomial distortion, though nowhere near as powerful.  As TPD has a finite
* and not too large number of possible terms (60), the coefficients for each
* can be stored in a fixed location in the dparm[] array.  A large part of the
* speedup then arises from evaluating the polynomial using Horner's scheme.
*
* Separate implementations for polynomials of each degree, and conditionals
* for 1D polynomials and 2D polynomials with and without the radial variable,
* ensure that unused terms mostly do not impose a significant computational
* overhead.
*
* The TPD terms are as follows:
*
*   0: 1     4: xx      12: xxxx      24: xxxxxx      40: xxxxxxxx
*            5: xy      13: xxxy      25: xxxxxy      41: xxxxxxxy
*   1: x     6: yy      14: xxyy      26: xxxxyy      42: xxxxxxyy
*   2: y                15: xyyy      27: xxxyyy      43: xxxxxyyy
*   3: r     7: xxx     16: yyyy      28: xxyyyy      44: xxxxyyyy
*            8: xxy                   29: xyyyyy      45: xxxyyyyy
*            9: xyy     17: xxxxx     30: yyyyyy      46: xxyyyyyy
*           10: yyy     18: xxxxy                     47: xyyyyyyy
*           11: rrr     19: xxxyy     31: xxxxxxx     48: yyyyyyyy
*                       20: xxyyy     32: xxxxxxy
*                       21: xyyyy     33: xxxxxyy     49: xxxxxxxxx
*                       22: yyyyy     34: xxxxyyy     50: xxxxxxxxy
*                       23: rrrrr     35: xxxyyyy     51: xxxxxxxyy
*                                     36: xxyyyyy     52: xxxxxxyyy
*                                     37: xyyyyyy     53: xxxxxyyyy
*                                     38: yyyyyyy     54: xxxxyyyyy
*                                     39: rrrrrrr     55: xxxyyyyyy
*                                                     56: xxyyyyyyy
*                                                     57: xyyyyyyyy
*                                                     58: yyyyyyyyy
*                                                     59: rrrrrrrrr
*
* where r = sqrt(xx + yy).  Note that even powers of r are excluded since they
* can be accomodated by powers of (xx + yy).
*
* TPV utilizes all terms up to 39.  The m in its PVi_ma keywords translates
* directly to the TPD coefficient number.
*
* SIP utilizes all terms except for 0, 1, 2, 3, 11, 23, 39, and 59.
* Its A_p_q, etc. keywords must be translated using a map (see sipset()).
*---------------------------------------------------------------------------*/

int tpdset(int j, struct disprm *dis)

{
  static const char *function = "tpdset";

  char   *fp, id[16];
  int    doradial, idp, k, m, ncoeff[2], ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  sprintf(id, "TPD on axis %d", j+1);


  /* TPD distortion. */
  if (dis->Nhat[j] < 1 || 2 < dis->Nhat[j]) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 1 or 2 entries, not %d", id,
      dis->Nhat[j]);
  }

  /* Find the number of parameters. */
  ncoeff[0] = 0;
  ncoeff[1] = 0;
  doradial  = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        /* TPD may provide a polynomial approximation for the inverse. */
        m = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 59) {
        if (ncoeff[m] < k+1) ncoeff[m] = k+1;

        /* Any radial terms? */
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (m = 0; m < 2; m++) {
    if (ncoeff[m] <= 4) {
      /* First degree. */
      ncoeff[m] = 4;
      distpd[m] = tpd1;
    } else if (ncoeff[m] <= 7) {
      /* Second degree. */
      ncoeff[m] = 7;
      distpd[m] = tpd2;
    } else if (ncoeff[m] <= 12) {
      /* Third degree. */
      ncoeff[m] = 12;
      distpd[m] = tpd3;
    } else if (ncoeff[m] <= 17) {
      /* Fourth degree. */
      ncoeff[m] = 17;
      distpd[m] = tpd4;
    } else if (ncoeff[m] <= 24) {
      /* Fifth degree. */
      ncoeff[m] = 24;
      distpd[m] = tpd5;
    } else if (ncoeff[m] <= 31) {
      /* Sixth degree. */
      ncoeff[m] = 31;
      distpd[m] = tpd6;
    } else if (ncoeff[m] <= 40) {
      /* Seventh degree. */
      ncoeff[m] = 40;
      distpd[m] = tpd7;
    } else if (ncoeff[m] <= 49) {
      /* Eighth degree. */
      ncoeff[m] = 49;
      distpd[m] = tpd8;
    } else if (ncoeff[m] <= 60) {
      /* Ninth degree. */
      ncoeff[m] = 60;
      distpd[m] = tpd9;
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid number of parameters (%d) for %s", ncoeff[m], id);
    }
  }

  /* disx2p() only uses the inverse TPD, if present, to provide a better */
  /* zeroth approximation. */
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


  /* Record indexing parameters. */
  niparm = 5;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* The first three are required by disprt(). */
  ndparm = ncoeff[0] + ncoeff[1];
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff[0];

  /* Flag for presence of radial terms. */
  dis->iparm[j][4] = doradial;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;
      } else {
        m = ncoeff[0];
      }

      sscanf(fp+4, "%d", &k);
      dis->dparm[j][m+k] = wcsutil_dpkey_double(keyp);
    }
  }

  return 0;
}

d2174 1
a2174 1
  if (degree[1]) {
d2178 168
@


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


5.4.1.2
log
@Moved the explanation of TPD to dis.c.  Reordered some functions.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.4.1.1 2015/04/21 14:44:28 mcalabre Exp mcalabre $
d1871 219
a2396 168

  return 0;
}

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

int tpdset(int j, struct disprm *dis)

{
  static const char *function = "tpdset";

  char   *fp, id[16];
  int    doradial, idp, k, m, ncoeff[2], ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  sprintf(id, "TPD on axis %d", j+1);


  /* TPD distortion. */
  if (dis->Nhat[j] < 1 || 2 < dis->Nhat[j]) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 1 or 2 entries, not %d", id,
      dis->Nhat[j]);
  }

  /* Find the number of parameters. */
  ncoeff[0] = 0;
  ncoeff[1] = 0;
  doradial  = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        /* TPD may provide a polynomial approximation for the inverse. */
        m = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 59) {
        if (ncoeff[m] < k+1) ncoeff[m] = k+1;

        /* Any radial terms? */
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (m = 0; m < 2; m++) {
    if (ncoeff[m] <= 4) {
      /* First degree. */
      ncoeff[m] = 4;
      distpd[m] = tpd1;
    } else if (ncoeff[m] <= 7) {
      /* Second degree. */
      ncoeff[m] = 7;
      distpd[m] = tpd2;
    } else if (ncoeff[m] <= 12) {
      /* Third degree. */
      ncoeff[m] = 12;
      distpd[m] = tpd3;
    } else if (ncoeff[m] <= 17) {
      /* Fourth degree. */
      ncoeff[m] = 17;
      distpd[m] = tpd4;
    } else if (ncoeff[m] <= 24) {
      /* Fifth degree. */
      ncoeff[m] = 24;
      distpd[m] = tpd5;
    } else if (ncoeff[m] <= 31) {
      /* Sixth degree. */
      ncoeff[m] = 31;
      distpd[m] = tpd6;
    } else if (ncoeff[m] <= 40) {
      /* Seventh degree. */
      ncoeff[m] = 40;
      distpd[m] = tpd7;
    } else if (ncoeff[m] <= 49) {
      /* Eighth degree. */
      ncoeff[m] = 49;
      distpd[m] = tpd8;
    } else if (ncoeff[m] <= 60) {
      /* Ninth degree. */
      ncoeff[m] = 60;
      distpd[m] = tpd9;
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid number of parameters (%d) for %s", ncoeff[m], id);
    }
  }

  /* disx2p() only uses the inverse TPD, if present, to provide a better */
  /* zeroth approximation. */
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


  /* Record indexing parameters. */
  niparm = 5;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* The first three are required by disprt(). */
  ndparm = ncoeff[0] + ncoeff[1];
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff[0];

  /* Flag for presence of radial terms. */
  dis->iparm[j][4] = doradial;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;
      } else {
        m = ncoeff[0];
      }

      sscanf(fp+4, "%d", &k);
      dis->dparm[j][m+k] = wcsutil_dpkey_double(keyp);
    }
  }
@


5.4.1.3
log
@Bug fix in sipset() uncovered by valgrind.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.4.1.2 2015/05/01 08:24:44 mcalabre Exp mcalabre $
d2174 1
a2174 1
  if (degree[1] > 0) {
@


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: dis.c,v 5.2.1.4 2015/04/21 02:36:06 mcalabre Exp mcalabre $
d40 3
d406 4
d441 1
a441 1
    for (k = 0; k < dis->iparm[j][0]; k++) {
d453 1
a453 1
    for (k = 0; k < dis->iparm[j][1]; k++) {
d478 18
a495 14
    } else if (dis->disp2x[j] == tpv1) {
      wcsprintf("  (= tpv1)\n");
    } else if (dis->disp2x[j] == tpv2) {
      wcsprintf("  (= tpv2)\n");
    } else if (dis->disp2x[j] == tpv3) {
      wcsprintf("  (= tpv3)\n");
    } else if (dis->disp2x[j] == tpv4) {
      wcsprintf("  (= tpv4)\n");
    } else if (dis->disp2x[j] == tpv5) {
      wcsprintf("  (= tpv5)\n");
    } else if (dis->disp2x[j] == tpv6) {
      wcsprintf("  (= tpv6)\n");
    } else if (dis->disp2x[j] == tpv7) {
      wcsprintf("  (= tpv7)\n");
d606 1
a606 1
    if ((dis->axmap[0] = calloc(naxis*naxis, sizeof(int))) == 0x0) {
d612 1
a612 1
      dis->axmap[j] = dis->axmap[j-1] + naxis;
d679 4
a682 1
  memset(dis->axmap[0],  0, naxis*naxis*sizeof(int));
d741 2
a742 2
      /* N.B. axis numbers in the map are 1-relative. */
      dis->axmap[j][jhat-1] = wcsutil_dpkey_int(keyp);
d780 1
a780 1
      if (dis->axmap[j][jhat] == 0) {
d788 1
a788 1
      if (dis->axmap[j][jhat] != 0) Nhat = jhat+1;
d807 6
d830 8
a837 1
    if (strcmp(dis->dtype[j], "TPV") == 0) {
d844 9
a852 1
    } else if (strcmp(dis->dtype[j], "Polynomial") == 0) {
d908 1
a908 2
        /* N.B. the axis numbers in the map are 1-relative. */
        axisj = dis->axmap[j][jhat] - 1;
d912 1
a912 1
      if ((status = (dis->disp2x[j])(dis->iparm[j], dis->dparm[j], Nhat,
d940 2
a941 2
  int convergence, iter, j, naxis, status;
  double dd, *dcrd0, *dcrd1, *delta, residual, *rcrd1;
d966 16
d1305 19
a1323 18
#define I_NIPARM  0	/* Full (allocated) length of iparm[].              */
#define I_NDPARM  1	/* No. of parameters in dparm[], excl. work space.  */
#define I_NIDX    2	/* No. of indexes in iparm[].                       */
#define I_LENDP   3	/* Full (allocated) length of dparm[].              */
#define I_K       4	/* No. of independent variables.                    */
#define I_M       5	/* No. of terms in the polynomial.                  */
#define I_NKPARM  6	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  7	/* No. of parameters used to define each term.      */
#define I_NVAR    8	/* No. of independent + auxiliary variables.        */
#define I_MNVAR   9	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  10	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   11	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  12	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 13	/* iparm offset for max powers.                     */
#define I_DPOFF  14	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  15	/* iparm offset for flags.                          */
#define I_IPOW   16	/* iparm offset for integral powers.                */
#define NIDX     17
d1346 1
d1552 130
a1683 1
  dis->disp2x[j] = dispoly;
d1686 67
d1759 1
d1872 218
d2098 1
a2098 1
  int    idp, k, ndparm;
d2115 2
a2116 1
  ndparm = 0;
d2128 5
d2147 1
d2151 1
a2151 1
    dis->disp2x[j] = tpv1;
d2155 1
a2155 1
    dis->disp2x[j] = tpv2;
d2159 1
a2159 1
    dis->disp2x[j] = tpv3;
d2163 1
a2163 1
    dis->disp2x[j] = tpv4;
d2167 1
a2167 1
    dis->disp2x[j] = tpv5;
d2171 1
a2171 1
    dis->disp2x[j] = tpv6;
d2175 1
a2175 1
    dis->disp2x[j] = tpv7;
d2177 1
d2186 2
a2187 1
  if ((dis->iparm[j] = calloc(2, sizeof(int))) == 0x0) {
d2191 8
a2198 3
  /* Parameters required by disprt(). */
  dis->iparm[j][0] = 2;
  dis->iparm[j][1] = ndparm;
d2212 1
d2224 181
a2404 1
int tpv1(
d2414 1
a2414 1
  if (i[1] != 4 || Nhat != 2) {
d2418 2
d2421 6
a2427 2
  s = u*u + v*v;
  r = sqrt(s);
d2429 93
a2521 2
  /* First degree. */
  *discrd = p[0] + u*p[1] + v*p[2] + r*p[3];
d2528 2
a2529 1
int tpv2(
d2539 1
a2539 1
  if (i[1] != 7 || Nhat != 2) {
d2543 2
d2546 6
a2552 2
  s = u*u + v*v;
  r = sqrt(s);
d2554 12
a2565 6
  /* Second degree. */
  *discrd =
         p[0]  + r*(p[3])
               + v*(p[2]  + v*(p[6]))
    + u*(p[1]  + v*(p[5])
    + u*(p[4]));
d2572 2
a2573 1
int tpv3(
d2583 1
a2583 1
  if (i[1] != 12 || Nhat != 2) {
d2587 2
d2590 6
a2596 2
  s = u*u + v*v;
  r = sqrt(s);
d2598 13
a2610 7
  /* Third degree. */
  *discrd =
         p[0]  + r*(p[3]  +            s*(p[11]))
               + v*(p[2]  + v*(p[6]  + v*(p[10])))
    + u*(p[1]  + v*(p[5]  + v*(p[9]))
    + u*(p[4]  + v*(p[8])
    + u*(p[7])));
d2617 2
a2618 1
int tpv4(
d2628 1
a2628 1
  if (i[1] != 17 || Nhat != 2) {
d2632 2
d2635 6
a2641 2
  s = u*u + v*v;
  r = sqrt(s);
d2643 14
a2656 8
  /* Fourth degree. */
  *discrd =
         p[0]  + r*(p[3]  +            s*(p[11]))
               + v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16]))))
    + u*(p[1]  + v*(p[5]  + v*(p[9]  + v*(p[15])))
    + u*(p[4]  + v*(p[8]  + v*(p[14]))
    + u*(p[7]  + v*(p[13])
    + u*(p[12]))));
d2663 2
a2664 1
int tpv5(
d2674 1
a2674 1
  if (i[1] != 24 || Nhat != 2) {
d2678 2
d2681 6
a2687 2
  s = u*u + v*v;
  r = sqrt(s);
d2689 15
a2703 9
  /* Fifth degree. */
  *discrd =
         p[0]  + r*(p[3]  +            s*(p[11] +            s*(p[23])))
               + v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22])))))
    + u*(p[1]  + v*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21]))))
    + u*(p[4]  + v*(p[8]  + v*(p[14] + v*(p[20])))
    + u*(p[7]  + v*(p[13] + v*(p[19]))
    + u*(p[12] + v*(p[18])
    + u*(p[17])))));
d2710 2
a2711 1
int tpv6(
d2721 1
a2721 1
  if (i[1] != 31 || Nhat != 2) {
d2725 2
d2728 6
a2734 2
  s = u*u + v*v;
  r = sqrt(s);
d2736 16
a2751 10
  /* Sixth degree. */
  *discrd =
         p[0]  + r*(p[3]  +            s*(p[11] +            s*(p[23])))
               + v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30]))))))
    + u*(p[1]  + v*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29])))))
    + u*(p[4]  + v*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28]))))
    + u*(p[7]  + v*(p[13] + v*(p[19] + v*(p[27])))
    + u*(p[12] + v*(p[18] + v*(p[26]))
    + u*(p[17] + v*(p[25])
    + u*(p[24]))))));
d2758 2
a2759 1
int tpv7(
d2769 1
a2769 1
  if (i[1] != 40 || Nhat != 2) {
d2773 2
d2776 6
a2782 2
  s = u*u + v*v;
  r = sqrt(s);
d2784 17
a2800 11
  /* Seventh degree. */
  *discrd =
         p[0]  + r*(p[3]  +            s*(p[11] +            s*(p[23] +            s*(p[39]))))
               + v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38])))))))
    + u*(p[1]  + v*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37]))))))
    + u*(p[4]  + v*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36])))))
    + u*(p[7]  + v*(p[13] + v*(p[19] + v*(p[27] + v*(p[35]))))
    + u*(p[12] + v*(p[18] + v*(p[26] + v*(p[34])))
    + u*(p[17] + v*(p[25] + v*(p[33]))
    + u*(p[24] + v*(p[32])
    + u*(p[31])))))));
@


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


5.3.1.2
log
@TPV, SIP, and if possible, the general Polynomial distortion function are
now implemented by the Template Polynomial Distortion (TPD), that being a
superset of TPV and SIP.  TPD, also handles 1D distortions and can be used
for inversions.  TPD efficiently handles 1D distortions and distortions
without radial terms, and is supported as a separate distortion type
defined by Paper IV keywords.  New functions: tpdset(), sipset(), and
pol2tpd().  All of the old tpv*() functions now become tpd*().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.3.1.1 2015/04/21 02:54:02 mcalabre Exp mcalabre $
a39 3
const int POLYNOMIAL = 0;
const int TPD        = 1;

a402 4
    wcsprintf("\n            ");
    for (i = naxis; i < 2*naxis; i++) {
      wcsprintf("%6d", dis->axmap[j][i]);
    }
d434 1
a434 1
    for (k = 0; k < dis->iparm[j][1]; k++) {
d446 1
a446 1
    for (k = 0; k < dis->iparm[j][2]; k++) {
d471 14
a484 18
    } else if (dis->disp2x[j] == tpd1) {
      wcsprintf("  (= tpd1)\n");
    } else if (dis->disp2x[j] == tpd2) {
      wcsprintf("  (= tpd2)\n");
    } else if (dis->disp2x[j] == tpd3) {
      wcsprintf("  (= tpd3)\n");
    } else if (dis->disp2x[j] == tpd4) {
      wcsprintf("  (= tpd4)\n");
    } else if (dis->disp2x[j] == tpd5) {
      wcsprintf("  (= tpd5)\n");
    } else if (dis->disp2x[j] == tpd6) {
      wcsprintf("  (= tpd6)\n");
    } else if (dis->disp2x[j] == tpd7) {
      wcsprintf("  (= tpd7)\n");
    } else if (dis->disp2x[j] == tpd8) {
      wcsprintf("  (= tpd8)\n");
    } else if (dis->disp2x[j] == tpd9) {
      wcsprintf("  (= tpd9)\n");
d595 1
a595 1
    if ((dis->axmap[0] = calloc(2*naxis*naxis, sizeof(int))) == 0x0) {
d601 1
a601 1
      dis->axmap[j] = dis->axmap[j-1] + 2*naxis;
d668 1
a668 4
  for (j = 0; j < 2*naxis*naxis; j++) {
    dis->axmap[0][j] = -1;
  }

d727 2
a728 2
      /* N.B. axis numbers in the map are 0-relative. */
      dis->axmap[j][jhat-1] = wcsutil_dpkey_int(keyp) - 1;
d766 1
a766 1
      if (dis->axmap[j][jhat] == -1) {
d774 1
a774 1
      if (dis->axmap[j][jhat] != -1) Nhat = jhat+1;
a792 6

    /* Construct the inverse axis map. */
    for (jhat = 0; jhat < Nhat; jhat++) {
      k = naxis + dis->axmap[j][jhat];
      dis->axmap[j][k] = jhat;
    }
d810 1
a810 8
    if (strcmp(dis->dtype[j], "TPD") == 0) {
      /* Template Polynomial Distortion". */
      if ((status = tpdset(j, dis))) {
        /* (Preserve the error message set by tpdset().) */
        return status;
      }

    } else if (strcmp(dis->dtype[j], "TPV") == 0) {
d817 1
a817 9
    } else if (strcmp(dis->dtype[j], "SIP") == 0) {
      /* Simple Imaging Polynomial (SIP). */
      if ((status = sipset(j, dis))) {
        /* (Preserve the error message set by sipset().) */
        return status;
      }

    } else if (strcmp(dis->dtype[j], "Polynomial")  == 0 ||
               strcmp(dis->dtype[j], "Polynomial*") == 0) {
d873 2
a874 1
        axisj = dis->axmap[j][jhat];
d878 1
a878 1
      if ((status = (dis->disp2x[j])(0, dis->iparm[j], dis->dparm[j], Nhat,
d906 2
a907 2
  int convergence, iter, j, jhat, naxis, Nhat, status;
  double dd, *dcrd0, *dcrd1, *delta, residual, *rcrd1, rtmp;
a931 16
  /* If available, use disprm::disx2p to improve the zeroth approximation. */
  for (j = 0; j < naxis; j++) {
    if (dis->disx2p[j]) {
      Nhat = dis->Nhat[j];
      if ((status = (dis->disx2p[j])(1, dis->iparm[j], dis->dparm[j], Nhat,
                                     discrd, &rtmp))) {
        return wcserr_set(DIS_ERRMSG(DISERR_DEDISTORT));
      }

      /* Using the inverse axis map. */
      jhat = dis->axmap[j][naxis+j];
      rawcrd[j] = dis->offset[j][jhat] + rtmp/dis->scale[j][jhat];
    }
  }


d1255 18
a1272 19
#define I_DTYPE   0	/* Distortion type code.                            */
#define I_NIPARM  1	/* Full (allocated) length of iparm[].              */
#define I_NDPARM  2	/* No. of parameters in dparm[], excl. work space.  */
#define I_NIDX    3	/* No. of indexes in iparm[].                       */
#define I_LENDP   4	/* Full (allocated) length of dparm[].              */
#define I_K       5	/* No. of independent variables.                    */
#define I_M       6	/* No. of terms in the polynomial.                  */
#define I_NKPARM  7	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  8	/* No. of parameters used to define each term.      */
#define I_NVAR    9	/* No. of independent + auxiliary variables.        */
#define I_MNVAR  10	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  11	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   12	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  13	/* dparm offset for integral powers of variables.   */
#define I_MAXPOW 14	/* iparm offset for max powers.                     */
#define I_DPOFF  15	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  16	/* iparm offset for flags.                          */
#define I_IPOW   17	/* iparm offset for integral powers.                */
#define NIDX     18
a1294 1
  iparm[I_DTYPE]  = POLYNOMIAL;
d1500 1
a1504 197
  /* Translate Polynomial to TPD if possible, it's much faster.  */
  /* However don't do it if the name was given as "Polynomial*". */
  if (strcmp(dis->dtype[j], "Polynomial") == 0) {
    pol2tpd(j, dis);
  }

  return 0;
}

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

int pol2tpd(int j, struct disprm *dis)

{
  static const char *function = "pol2tpd";

  static const int map[][10] = {{ 0,  2,  6, 10, 16, 22, 30, 38, 48, 58},
                                { 1,  5,  9, 15, 21, 29, 37, 47, 57, -1},
                                { 4,  8, 14, 20, 28, 36, 46, 56, -1, -1},
                                { 7, 13, 19, 27, 35, 45, 55, -1, -1, -1},
                                {12, 18, 26, 34, 44, 54, -1, -1, -1, -1},
                                {17, 25, 33, 43, 53, -1, -1, -1, -1, -1},
                                {24, 32, 42, 52, -1, -1, -1, -1, -1, -1},
                                {31, 41, 51, -1, -1, -1, -1, -1, -1, -1},
                                {40, 50, -1, -1, -1, -1, -1, -1, -1, -1},
                                {49, -1, -1, -1, -1, -1, -1, -1, -1, -1}};

  int deg, degree, *iflgp, *iparm, *ipowp, jhat, K, m, n, ndparm, Nhat,
      niparm, p[2], *tpd_iparm;
  double *dparm, *dpolp, *tpd_dparm;
  struct wcserr **err;

  /* Initialize. */
  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  iparm = dis->iparm[j];
  dparm = dis->dparm[j];


  /* Check the number of independent variables, no more than two. */
  Nhat = dis->Nhat[j];
  if (2 < Nhat) return -1;

  /* Check auxiliaries: only one is allowed... */
  K = iparm[I_K];
  if (1 < K) return -1;
  if (K) {
    /* ...and it must be radial. */
    if (dparm[0] != 0.0) return -1;
    if (dparm[1] != 1.0) return -1;
    if (dparm[2] != 1.0) return -1;
    if (dparm[3] != 0.5) return -1;
    if (dparm[4] != 2.0) return -1;
    if (dparm[5] != 2.0) return -1;
  }

  /* Check powers... */
  iflgp = iparm + iparm[I_FLAGS];
  ipowp = iparm + iparm[I_IPOW];
  degree = 0;
  for (m = 0; m < iparm[I_M]; m++) {
    deg = 0;
    for (jhat = 0; jhat < Nhat; jhat++) {
      /* ...they must be positive integral. */
      if (*iflgp == 0)  return -1;
      if (*ipowp < 0)   return -1;
      deg += *ipowp;
      iflgp++;
      ipowp++;
    }

    /* The polynomial degree can't be greater than 9. */
    if (9 < deg) return -1;

    if (K) {
      /* Likewise for the radial variable. */
      if (*iflgp == 0)  return -1;
      if (*ipowp) {
        if (*ipowp < 0) return -1;
        if (9 < *ipowp) return -1;

        /* Can't mix the radial and other terms. */
        if (deg)        return -1;

        /* Can't have even powers of the radial variable. */
        deg = *ipowp;
        if (!(deg%2))   return -1;
      }
      iflgp++;
      ipowp++;
    }

    if (degree < deg) degree = deg;
  }


  /* OK, it ticks all the boxes.  Now translate it. */
  if (degree == 1) {
    ndparm = 4;
    dis->disp2x[j] = tpd1;
  } else if (degree == 2) {
    ndparm = 7;
    dis->disp2x[j] = tpd2;
  } else if (degree == 3) {
    ndparm = 12;
    dis->disp2x[j] = tpd3;
  } else if (degree == 4) {
    ndparm = 17;
    dis->disp2x[j] = tpd4;
  } else if (degree == 5) {
    ndparm = 24;
    dis->disp2x[j] = tpd5;
  } else if (degree == 6) {
    ndparm = 31;
    dis->disp2x[j] = tpd6;
  } else if (degree == 7) {
    ndparm = 40;
    dis->disp2x[j] = tpd7;
  } else if (degree == 8) {
    ndparm = 49;
    dis->disp2x[j] = tpd8;
  } else if (degree == 9) {
    ndparm = 60;
    dis->disp2x[j] = tpd9;
  }

  /* No specialist de-distortions. */
  dis->disx2p[j] = 0x0;

  /* Record indexing parameters. */
  niparm = 5;
  if ((tpd_iparm = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* The first three are required by disprt(). */
  tpd_iparm[0] = TPD;
  tpd_iparm[1] = niparm;
  tpd_iparm[2] = ndparm;
  tpd_iparm[3] = ndparm;

  /* Flag for presence of radial terms. */
  tpd_iparm[4] = K;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((tpd_dparm = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  ipowp = iparm + iparm[I_IPOW];
  dpolp = dparm + iparm[I_DPOLY];
  for (m = 0; m < iparm[I_M]; m++) {
    if (K && ipowp[Nhat]) {
      /* The radial variable. */
      switch (ipowp[Nhat]) {
      case 1:
        tpd_dparm[3]  = *dpolp;
        break;
      case 3:
        tpd_dparm[11] = *dpolp;
        break;
      case 5:
        tpd_dparm[23] = *dpolp;
        break;
      case 7:
        tpd_dparm[39] = *dpolp;
        break;
      case 9:
        tpd_dparm[59] = *dpolp;
        break;
      }

    } else {
      /* The independent variables. */
      p[0] = p[1] = 0;
      for (jhat = 0; jhat < Nhat; jhat++) {
        p[jhat] = ipowp[jhat];
      }

      n = map[p[0]][p[1]];
      tpd_dparm[n] = *dpolp;
    }


    ipowp += iparm[I_NVAR];
    dpolp += iparm[I_NVAR] + 1;
  }


  /* Switch from Polynomial to TPD. */
  free(iparm);
  free(dparm);
  dis->iparm[j] = tpd_iparm;
  dis->dparm[j] = tpd_dparm;

a1510 1
  int inverse,
a1622 218
/*----------------------------------------------------------------------------
* The "Template Polynomial Distortion" (TPD) is a superset of the TPV and SIP
* polynomial distortions that also supports 1D usage.  Like TPV and SIP, the
* form of the polynomial is fixed (the "template") and only the coefficients
* for the required terms are set non-zero.  TPD generalizes TPV in going to
* 9th degree, and SIP by accomodating TPV's linear and radial terms.
*
* In typical applications, TPD is considerably faster than the generalized
* Polynomial distortion, though nowhere near as powerful.  As TPD has a finite
* and not too large number of possible terms (60), the coefficients for each
* can be stored in a fixed location in the dparm[] array.  A large part of the
* speedup then arises from evaluating the polynomial using Horner's scheme.
*
* Separate implementations for polynomials of each degree, and conditionals
* for 1D polynomials and 2D polynomials with and without the radial variable,
* ensure that unused terms mostly do not impose a significant computational
* overhead.
*
* The TPD terms are as follows:
*
*   0: 1     4: xx      12: xxxx      24: xxxxxx      40: xxxxxxxx
*            5: xy      13: xxxy      25: xxxxxy      41: xxxxxxxy
*   1: x     6: yy      14: xxyy      26: xxxxyy      42: xxxxxxyy
*   2: y                15: xyyy      27: xxxyyy      43: xxxxxyyy
*   3: r     7: xxx     16: yyyy      28: xxyyyy      44: xxxxyyyy
*            8: xxy                   29: xyyyyy      45: xxxyyyyy
*            9: xyy     17: xxxxx     30: yyyyyy      46: xxyyyyyy
*           10: yyy     18: xxxxy                     47: xyyyyyyy
*           11: rrr     19: xxxyy     31: xxxxxxx     48: yyyyyyyy
*                       20: xxyyy     32: xxxxxxy
*                       21: xyyyy     33: xxxxxyy     49: xxxxxxxxx
*                       22: yyyyy     34: xxxxyyy     50: xxxxxxxxy
*                       23: rrrrr     35: xxxyyyy     51: xxxxxxxyy
*                                     36: xxyyyyy     52: xxxxxxyyy
*                                     37: xyyyyyy     53: xxxxxyyyy
*                                     38: yyyyyyy     54: xxxxyyyyy
*                                     39: rrrrrrr     55: xxxyyyyyy
*                                                     56: xxyyyyyyy
*                                                     57: xyyyyyyyy
*                                                     58: yyyyyyyyy
*                                                     59: rrrrrrrrr
*
* where r = sqrt(xx + yy).  Note that even powers of r are excluded since they
* can be accomodated by powers of (xx + yy).
*
* TPV utilizes all terms up to 39.  The m in its PVi_ma keywords translates
* directly to the TPD coefficient number.
*
* SIP utilizes all terms except for 0, 1, 2, 3, 11, 23, 39, and 59.
* Its A_p_q, etc. keywords must be translated using a map (see sipset()).
*---------------------------------------------------------------------------*/

int tpdset(int j, struct disprm *dis)

{
  static const char *function = "tpdset";

  char   *fp, id[16];
  int    doradial, idp, k, m, ncoeff[2], ndparm, niparm;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  sprintf(id, "TPD on axis %d", j+1);


  /* TPD distortion. */
  if (dis->Nhat[j] < 1 || 2 < dis->Nhat[j]) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 1 or 2 entries, not %d", id,
      dis->Nhat[j]);
  }

  /* Find the number of parameters. */
  ncoeff[0] = 0;
  ncoeff[1] = 0;
  doradial  = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        /* TPD may provide a polynomial approximation for the inverse. */
        m = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 59) {
        if (ncoeff[m] < k+1) ncoeff[m] = k+1;

        /* Any radial terms? */
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (m = 0; m < 2; m++) {
    if (ncoeff[m] <= 4) {
      /* First degree. */
      ncoeff[m] = 4;
      distpd[m] = tpd1;
    } else if (ncoeff[m] <= 7) {
      /* Second degree. */
      ncoeff[m] = 7;
      distpd[m] = tpd2;
    } else if (ncoeff[m] <= 12) {
      /* Third degree. */
      ncoeff[m] = 12;
      distpd[m] = tpd3;
    } else if (ncoeff[m] <= 17) {
      /* Fourth degree. */
      ncoeff[m] = 17;
      distpd[m] = tpd4;
    } else if (ncoeff[m] <= 24) {
      /* Fifth degree. */
      ncoeff[m] = 24;
      distpd[m] = tpd5;
    } else if (ncoeff[m] <= 31) {
      /* Sixth degree. */
      ncoeff[m] = 31;
      distpd[m] = tpd6;
    } else if (ncoeff[m] <= 40) {
      /* Seventh degree. */
      ncoeff[m] = 40;
      distpd[m] = tpd7;
    } else if (ncoeff[m] <= 49) {
      /* Eighth degree. */
      ncoeff[m] = 49;
      distpd[m] = tpd8;
    } else if (ncoeff[m] <= 60) {
      /* Ninth degree. */
      ncoeff[m] = 60;
      distpd[m] = tpd9;
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid number of parameters (%d) for %s", ncoeff[m], id);
    }
  }

  /* disx2p() only uses the inverse TPD, if present, to provide a better */
  /* zeroth approximation. */
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


  /* Record indexing parameters. */
  niparm = 5;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* The first three are required by disprt(). */
  ndparm = ncoeff[0] + ncoeff[1];
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff[0];

  /* Flag for presence of radial terms. */
  dis->iparm[j][4] = doradial;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPD.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;
      } else {
        m = ncoeff[0];
      }

      sscanf(fp+4, "%d", &k);
      dis->dparm[j][m+k] = wcsutil_dpkey_double(keyp);
    }
  }

  return 0;
}

d1631 1
a1631 1
  int    doradial, idp, k, ndparm, niparm;
d1648 1
a1648 2
  ndparm   = 0;
  doradial = 0;
a1659 5
	/* Any radial terms? */
        if (k == 3 || k == 11 || k == 23 || k == 39 || k == 59) {
          doradial = 1;
        }

a1673 1
  /* TPD is going to do the dirty work. */
d1677 1
a1677 1
    dis->disp2x[j] = tpd1;
d1681 1
a1681 1
    dis->disp2x[j] = tpd2;
d1685 1
a1685 1
    dis->disp2x[j] = tpd3;
d1689 1
a1689 1
    dis->disp2x[j] = tpd4;
d1693 1
a1693 1
    dis->disp2x[j] = tpd5;
d1697 1
a1697 1
    dis->disp2x[j] = tpd6;
d1701 1
a1701 1
    dis->disp2x[j] = tpd7;
a1702 1
    /* Could go to ninth degree, but that wouldn't be legit. */
d1711 1
a1711 2
  niparm = 5;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
d1715 3
a1717 8
  /* The first three are required by disprt(). */
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ndparm;

  /* Flag for presence of radial terms. */
  dis->iparm[j][4] = doradial;
a1730 1
    /* One-to-one correspondence between TPV and TPD coefficients. */
d1742 1
a1742 181
int sipset(int j, struct disprm *dis)

{
  static const char *function = "sipset";

  static const int map[][10] = {{ 0,  2,  6, 10, 16, 22, 30, 38, 48, 58},
                                { 1,  5,  9, 15, 21, 29, 37, 47, 57, -1},
                                { 4,  8, 14, 20, 28, 36, 46, 56, -1, -1},
                                { 7, 13, 19, 27, 35, 45, 55, -1, -1, -1},
                                {12, 18, 26, 34, 44, 54, -1, -1, -1, -1},
                                {17, 25, 33, 43, 53, -1, -1, -1, -1, -1},
                                {24, 32, 42, 52, -1, -1, -1, -1, -1, -1},
                                {31, 41, 51, -1, -1, -1, -1, -1, -1, -1},
                                {40, 50, -1, -1, -1, -1, -1, -1, -1, -1},
                                {49, -1, -1, -1, -1, -1, -1, -1, -1, -1}};

  char   *fp, id[16];
  int    deg, degree[2], idp, m, ncoeff[2], ndparm, niparm, p, q;
  struct dpkey *keyp;
  struct wcserr **err;
  int (*(distpd[2]))(DISP2X_ARGS);

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  sprintf(id, "SIP on axis %d", j+1);


  /* Simple Imaging Polynomial. */
  if (dis->Nhat[j] != 2) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
  }

  /* Find the polynomial degree, at least 1 for the forward function. */
  degree[0] =  1;
  degree[1] = -1;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "SIP.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;

      } else if (strncmp(fp, "REV.", 4) == 0) {
        /* SIP uses a polynomial approximation for the inverse. */
        m = 1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 4;
      sscanf(fp, "%d_%d", &p, &q);
      deg = p + q;
      if (p < 0 || 9 < p || q < 0 || 9 < q || 9 < deg) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid powers (%d, %d) for %s: %s", p, q, id, keyp->field);
      }

      if (degree[m] < deg) degree[m] = deg;

    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  if (degree[1] == 0 ) degree[1] = 1;

  /* TPD is going to do the dirty work. */
  distpd[0] = 0x0;
  distpd[1] = 0x0;
  for (m = 0; m < 2; m++) {
    ncoeff[m] = 0;
    if (degree[m] == 1) {
      ncoeff[m] = 4;
      distpd[m] = tpd1;
    } else if (degree[m] == 2) {
      ncoeff[m] = 7;
      distpd[m] = tpd2;
    } else if (degree[m] == 3) {
      ncoeff[m] = 12;
      distpd[m] = tpd3;
    } else if (degree[m] == 4) {
      ncoeff[m] = 17;
      distpd[m] = tpd4;
    } else if (degree[m] == 5) {
      ncoeff[m] = 24;
      distpd[m] = tpd5;
    } else if (degree[m] == 6) {
      ncoeff[m] = 31;
      distpd[m] = tpd6;
    } else if (degree[m] == 7) {
      ncoeff[m] = 40;
      distpd[m] = tpd7;
    } else if (degree[m] == 8) {
      ncoeff[m] = 49;
      distpd[m] = tpd8;
    } else if (degree[m] == 9) {
      ncoeff[m] = 60;
      distpd[m] = tpd9;
    }
  }

  /* SIP uses a polynomial approximation to the inverse.  It's not very    */
  /* accurate but may provide disx2p() with a better zeroth approximation. */
  dis->disp2x[j] = distpd[0];
  dis->disx2p[j] = distpd[1];


  /* Record indexing parameters. */
  niparm = 5;
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* The first three are required by disprt(). */
  ndparm = ncoeff[0] + ncoeff[1];
  dis->iparm[j][0] = TPD;
  dis->iparm[j][1] = niparm;
  dis->iparm[j][2] = ndparm;
  dis->iparm[j][3] = ncoeff[0];

  /* SIP never needs the radial terms. */
  dis->iparm[j][4] = 0;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "SIP.", 4) == 0) {
      fp += 4;
      if (strncmp(fp, "FWD.", 4) == 0) {
        m = 0;
      } else {
        m = ncoeff[0];
      }

      sscanf(fp+4, "%d_%d", &p, &q);

      /* Map to TPD coefficient number. */
      m += map[p][q];

      dis->dparm[j][m] = wcsutil_dpkey_double(keyp);
    }
  }

  /* The SIP distortion is an additive correction to the pixel coordinate, */
  /* whereas we want the value of the pixel coordinate after distortion.   */
  /* Note also that SIP has no axis mapping, i.e. jhat = j always.         */
  m = j + 1;
  dis->dparm[j][m] += 1.0;
  if (degree[1]) {
    dis->dparm[j][ncoeff[0]+m] += 1.0;
  }


  return 0;
}

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

int tpd1(
  int inverse,
d1752 1
a1752 1
  if (i[3] != 4 || 2 < Nhat) {
a1755 2
  if (inverse) p += i[3];

d1757 3
d1762 1
a1762 14
  *discrd = p[0] + u*p[1];

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd += v*p[2];

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*p[3];
  }
d1769 1
a1769 2
int tpd2(
  int inverse,
d1779 1
a1779 1
  if (i[3] != 7 || 2 < Nhat) {
a1782 2
  if (inverse) p += i[3];

d1784 3
d1789 5
a1793 16
  *discrd = p[0] + u*(p[1] + u*(p[4]));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]))
    + u*(p[5])*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*p[3];
  }
d1800 1
a1800 2
int tpd3(
  int inverse,
d1810 1
a1810 1
  if (i[3] != 12 || 2 < Nhat) {
a1813 2
  if (inverse) p += i[3];

d1815 3
d1820 6
a1825 17
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7])));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10])))
    + u*(p[5]  + v*(p[9])
    + u*(p[8]))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11]));
  }
d1832 1
a1832 2
int tpd4(
  int inverse,
d1842 1
a1842 1
  if (i[3] != 17 || 2 < Nhat) {
a1845 2
  if (inverse) p += i[3];

d1847 3
d1852 7
a1858 18
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12]))));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16]))))
    + u*(p[5]  + v*(p[9]  + v*(p[15]))
    + u*(p[8]  + v*(p[14])
    + u*(p[13])))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11]));
  }
d1865 1
a1865 2
int tpd5(
  int inverse,
d1875 1
a1875 1
  if (i[3] != 24 || 2 < Nhat) {
a1878 2
  if (inverse) p += i[3];

d1880 3
d1885 8
a1892 19
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17])))));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22])))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21])))
    + u*(p[8]  + v*(p[14] + v*(p[20]))
    + u*(p[13] + v*(p[19])
    + u*(p[18]))))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23])));
  }
d1899 1
a1899 2
int tpd6(
  int inverse,
d1909 1
a1909 1
  if (i[3] != 31 || 2 < Nhat) {
a1912 2
  if (inverse) p += i[3];

d1914 3
d1919 9
a1927 20
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24]))))));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30]))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29]))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28])))
    + u*(p[13] + v*(p[19] + v*(p[27]))
    + u*(p[18] + v*(p[26])
    + u*(p[25])))))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23])));
  }
d1934 1
a1934 2
int tpd7(
  int inverse,
d1944 1
a1944 1
  if (i[3] != 40 || 2 < Nhat) {
a1947 2
  if (inverse) p += i[3];

d1949 3
d1954 10
a1963 118
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24] + u*(p[31])))))));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38])))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37])))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36]))))
    + u*(p[13] + v*(p[19] + v*(p[27] + v*(p[35])))
    + u*(p[18] + v*(p[26] + v*(p[34]))
    + u*(p[25] + v*(p[33])
    + u*(p[32]))))))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23] + s*(p[39]))));
  }

  return 0;
}

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

int tpd8(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  double r, s, u, v;

  if (i[3] != 49 || 2 < Nhat) {
    return 1;
  }

  if (inverse) p += i[3];

  u = rawcrd[0];

  /* Eighth degree. */
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24] + u*(p[31] + u*(p[40]))))))));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38] + v*(p[48]))))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37] + v*(p[47]))))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36] + v*(p[46])))))
    + u*(p[13] + v*(p[19] + v*(p[27] + v*(p[35] + v*(p[45]))))
    + u*(p[18] + v*(p[26] + v*(p[34] + v*(p[44])))
    + u*(p[25] + v*(p[33] + v*(p[43]))
    + u*(p[32] + v*(p[42])
    + u*(p[41])))))))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23] + s*(p[39]))));
  }

  return 0;
}

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

int tpd9(
  int inverse,
  const int i[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  double r, s, u, v;

  if (i[3] != 60 || 2 < Nhat) {
    return 1;
  }

  if (inverse) p += i[3];

  u = rawcrd[0];

  /* Ninth degree. */
  *discrd = p[0] + u*(p[1] + u*(p[4] + u*(p[7] + u*(p[12] + u*(p[17] + u*(p[24] + u*(p[31] + u*(p[40] + u*(p[49])))))))));

  if (Nhat == 1) return 0;

  v = rawcrd[1];

  *discrd +=
      v*(p[2]  + v*(p[6]  + v*(p[10] + v*(p[16] + v*(p[22] + v*(p[30] + v*(p[38] + v*(p[48] + v*(p[58])))))))))
    + u*(p[5]  + v*(p[9]  + v*(p[15] + v*(p[21] + v*(p[29] + v*(p[37] + v*(p[47] + v*(p[57])))))))
    + u*(p[8]  + v*(p[14] + v*(p[20] + v*(p[28] + v*(p[36] + v*(p[46] + v*(p[56]))))))
    + u*(p[13] + v*(p[19] + v*(p[27] + v*(p[35] + v*(p[45] + v*(p[55])))))
    + u*(p[18] + v*(p[26] + v*(p[34] + v*(p[44] + v*(p[54]))))
    + u*(p[25] + v*(p[33] + v*(p[43] + v*(p[53])))
    + u*(p[32] + v*(p[42] + v*(p[52]))
    + u*(p[41] + v*(p[51])
    + u*(p[50]))))))))*v;

  if (i[4]) {
    s = u*u + v*v;
    r = sqrt(s);

    *discrd += r*(p[3] + s*(p[11] + s*(p[23] + s*(p[39] + s*(p[59])))));
  }
@


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: dis.c,v 5.1.1.8 2015/04/15 09:09:25 mcalabre Exp mcalabre $
d171 1
a171 1
        if ((dis->dtype = calloc(naxis, sizeof(char [16]))) == 0x0) {
d228 1
a228 1
  memset(dis->dtype,  0, naxis*sizeof(char [16]));
d267 1
a267 1
  memcpy(disdst->dtype, dissrc->dtype, naxis*sizeof(char [16]));
d352 1
a352 1
  int i, j, k;
d360 4
d367 1
a367 1
  wcsprintf("      naxis: %d\n", dis->naxis);
d370 1
a370 1
  for (j = 0; j < dis->naxis; j++) {
d389 1
a389 1
  for (j = 0; j < dis->naxis; j++) {
d398 1
a398 1
  for (j = 0; j < dis->naxis; j++) {
d400 1
a400 1
    for (i = 0; i < dis->naxis; i++) {
d408 1
a408 1
  for (j = 0; j < dis->naxis; j++) {
d414 1
a414 1
  for (j = 0; j < dis->naxis; j++) {
d416 1
a416 1
    for (i = 0; i < dis->naxis; i++) {
d423 1
a423 1
  for (j = 0; j < dis->naxis; j++) {
d425 1
a425 1
    for (i = 0; i < dis->naxis; i++) {
d432 1
a432 1
  for (j = 0; j < dis->naxis; j++) {
d444 1
a444 1
  for (j = 0; j < dis->naxis; j++) {
d466 1
a466 1
  for (j = 0; j < dis->naxis; j++) {
d469 3
a471 1
    if (dis->disp2x[j] == tpv1) {
d490 1
a490 1
  for (j = 0; j < dis->naxis; j++) {
d519 2
a520 2
  char   *fp;
  int    i, idp, j, k, naxis, ndis, Nhat, status;
d530 33
d601 1
a601 1
      dis->axmap[j]  = dis->axmap[j-1]  + naxis;
d636 1
a636 1
      dis->scale[j]  = dis->scale[j-1]  + naxis;
a648 7
    /* Carve up the 2D arrays. */
    for (j = 1; j < naxis; j++) {
      dis->axmap[j]  = dis->axmap[j-1]  + naxis;
      dis->offset[j] = dis->offset[j-1] + naxis;
      dis->scale[j]  = dis->scale[j-1]  + naxis;
    }

d689 6
d710 1
a710 1
      Nhat = keyp->value.i;
d720 2
a721 2
      sscanf(fp+5, "%d", &i);
      if (i < 0 || naxis < i) {
d724 1
a724 1
          dis->dtype[j], keyp->field, i);
d727 2
a728 1
      dis->axmap[j][i-1] = keyp->value.i;
d731 2
a732 2
      sscanf(fp+7, "%d", &i);
      dis->offset[j][i-1] = keyp->value.f;
d735 2
a736 2
      sscanf(fp+6, "%d", &i);
      dis->scale[j][i-1] = keyp->value.f;
d740 1
a740 1
  /* Sanity check on the axis maps. */
d742 30
d773 2
a774 2
    for (i = 0; i < naxis; i++) {
      if (dis->axmap[j][i] != 0) Nhat = i+1;
d783 4
a786 10
    for (i = 0; i < Nhat; i++) {
      if (dis->axmap[j][i] == 0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid axis map for %s distortion on axis %d", dis->dtype[j],
          j+1);
      }

      /* Check uniqueness. */
      for (k = 0; k < i; k++) {
        if (dis->axmap[j][i] == dis->axmap[j][k]) {
d809 7
d817 1
a817 2
    /* Invoke the specific setup functions for each distortion. */
    if (strcmp(dis->dtype[j], "Polynomial") == 0) {
a823 7
    } else if (strcmp(dis->dtype[j], "TPV") == 0) {
      /* The TPV "projection" is a special case. */
      if ((status = tpvset(j, dis))) {
        /* (Preserve the error message set by tpvset().) */
        return status;
      }

d848 2
a849 2
  int axisi, i, j, naxis, Nhat, status;
  double dtmp, *tmpcrd;
d867 3
d872 1
a872 1
      for (i = 0; i < Nhat; i++) {
d874 2
a875 2
        axisi = dis->axmap[j][i] - 1;
        tmpcrd[i] = (rawcrd[axisi] - dis->offset[j][i])*dis->scale[j][i];
d1132 1
a1132 1
      wcserr_set(DIS_ERRMSG(status));
d1147 3
a1149 1
      if (maxdis && (dpix = fabs(dpix)) > maxdis[j]) maxdis[j] = dpix;
d1158 3
a1160 1
    if (maxtot && *maxtot < totdis) *maxtot = totdis;
d1233 1
a1233 1
      K = keyp->value.i;
d1235 1
a1235 1
      M = keyp->value.i;
d1373 1
a1373 1
      dparm[i] = keyp->value.f;
d1392 1
a1392 1
        dparm[i] = keyp->value.f;
d1404 1
a1404 1
        power = keyp->value.f;
d1417 1
a1417 1
        power = keyp->value.f;
d1501 1
a1501 1
  /* No specialist deprojections. */
d1653 1
a1653 5
    if ((fp = strpbrk(keyp->field, ".")) == 0x0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid field name for %s: %s", id, keyp->field);
    }
    fp++;
d1707 3
d1729 6
a1734 3
    fp = strpbrk(keyp->field, ".")+5;
    sscanf(fp, "%d:", &k);
    dis->dparm[j][k] = keyp->value.f;
a1735 4


  /* No specialist deprojections. */
  dis->disx2p[j] = 0x0;
@


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


5.2.1.2
log
@disprm::dtype changed from char[16] to char[72].  More armour plating
for disset() and friends.  They also use new utility functions
wcsutil_dpkey_int() and wcsutil_dpkey_double() to extract numeric values
from a dpkey struct.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.2.1.1 2015/04/15 12:39:14 mcalabre Exp mcalabre $
d171 1
a171 1
        if ((dis->dtype = calloc(naxis, sizeof(char [72]))) == 0x0) {
d228 1
a228 1
  memset(dis->dtype,  0, naxis*sizeof(char [72]));
d513 1
a513 1
  char   *dpq, *fp;
a523 33
  /* Do basic checks. */
  if (dis->ndp < 0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "disprm::ndp is negative (%d)", dis->ndp);
  }

  ndis = 0;
  for (j = 0; j < naxis; j++) {
    if (strlen(dis->dtype[j])) {
      ndis++;
      break;
    }
  }

  if (dis->ndp) {
    if (dis->dp[0].field[1] == 'P') {
      dpq = "DPja";
    } else if (dis->dp[0].field[1] == 'Q') {
      dpq = "DQia";
    } else {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "disprm::dp[0].field (%s) is invalid", dis->dp[0].field);
    }

  } else {
    if (ndis) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "No DPja or DQia keywords, NAXES at least is required for each"
        "distortion");
    }
  }


a656 6
    /* Check that they're all one kind or the other. */
    if (dis->dp[0].field[1] != dpq[1]) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "disprm::dp appears to contain a mix of DPja and DQia keys");
    }

d672 1
a672 1
      Nhat = wcsutil_dpkey_int(keyp);
d689 1
a689 1
      dis->axmap[j][i-1] = wcsutil_dpkey_int(keyp);
d693 1
a693 1
      dis->offset[j][i-1] = wcsutil_dpkey_double(keyp);
d697 1
a697 1
      dis->scale[j][i-1] = wcsutil_dpkey_double(keyp);
d701 1
a701 1
  /* Set defaults and do sanity checks on axmap[][].  */
a702 30
    if (strlen(dis->dtype[j]) == 0) {
      /* No distortion on this axis, check that there are no parameters. */
      keyp = dis->dp;
      for (idp = 0; idp < dis->ndp; idp++, keyp++) {
        if (keyp->j == j+1) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
            "No distortion type, yet %s keyvalues are present for axis %d",
            dpq, j+1);
        }
      }

      continue;
    }

    /* N.B. NAXES (Nhat) has no default value. */
    if (dis->Nhat[j] <= 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "%s.NAXES was not set (or bad) for %s distortion on axis %d",
        dpq, dis->dtype[j], j+1);
    }

    /* Set defaults for axmap[][]. */
    Nhat = dis->Nhat[j];
    for (i = 0; i < Nhat; i++) {
      if (dis->axmap[j][i] == 0) {
        dis->axmap[j][i] = i;
      }
    }

    /* Sanity check on the length of the axis map. */
a713 1
    /* Check uniqueness of entries in the axis map. */
d715 7
d1164 1
a1164 1
      K = wcsutil_dpkey_int(keyp);
d1166 1
a1166 1
      M = wcsutil_dpkey_int(keyp);
d1304 1
a1304 1
      dparm[i] = wcsutil_dpkey_double(keyp);
d1323 1
a1323 1
        dparm[i] = wcsutil_dpkey_double(keyp);
d1335 1
a1335 1
        power = wcsutil_dpkey_double(keyp);
d1348 1
a1348 1
        power = wcsutil_dpkey_double(keyp);
d1584 5
a1588 1
    fp = strpbrk(keyp->field, ".") + 1;
d1661 3
a1663 6
    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "TPV.", 4) == 0) {
      sscanf(fp+4, "%d", &k);
      dis->dparm[j][k] = wcsutil_dpkey_double(keyp);
    }
@


5.2.1.3
log
@Trivial changes - use of temporary variables, renaming of some variables,
insignificant rearrangement of code, etc.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.2.1.2 2015/04/18 07:46:19 mcalabre Exp mcalabre $
d352 1
a352 1
  int i, j, k, naxis;
a359 4

  naxis = dis->naxis;


d363 1
a363 1
  wcsprintf("      naxis: %d\n", naxis);
d366 1
a366 1
  for (j = 0; j < naxis; j++) {
d385 1
a385 1
  for (j = 0; j < naxis; j++) {
d394 1
a394 1
  for (j = 0; j < naxis; j++) {
d396 1
a396 1
    for (i = 0; i < naxis; i++) {
d404 1
a404 1
  for (j = 0; j < naxis; j++) {
d410 1
a410 1
  for (j = 0; j < naxis; j++) {
d412 1
a412 1
    for (i = 0; i < naxis; i++) {
d419 1
a419 1
  for (j = 0; j < naxis; j++) {
d421 1
a421 1
    for (i = 0; i < naxis; i++) {
d428 1
a428 1
  for (j = 0; j < naxis; j++) {
d440 1
a440 1
  for (j = 0; j < naxis; j++) {
d462 1
a462 1
  for (j = 0; j < naxis; j++) {
d465 1
a465 3
    if (dis->disp2x[j] == dispoly) {
      wcsprintf("  (= dispoly)\n");
    } else if (dis->disp2x[j] == tpv1) {
d484 1
a484 1
  for (j = 0; j < naxis; j++) {
d514 1
a514 1
  int    idp, j, jhat, k, naxis, ndis, Nhat, status;
d595 1
a595 1
      dis->axmap[j] = dis->axmap[j-1] + naxis;
d630 1
a630 1
      dis->scale[j] = dis->scale[j-1] + naxis;
d643 7
d721 2
a722 2
      sscanf(fp+5, "%d", &jhat);
      if (jhat < 0 || naxis < jhat) {
d725 1
a725 1
          dis->dtype[j], keyp->field, jhat);
d728 1
a728 2
      /* N.B. axis numbers in the map are 1-relative. */
      dis->axmap[j][jhat-1] = wcsutil_dpkey_int(keyp);
d731 2
a732 2
      sscanf(fp+7, "%d", &jhat);
      dis->offset[j][jhat-1] = wcsutil_dpkey_double(keyp);
d735 2
a736 2
      sscanf(fp+6, "%d", &jhat);
      dis->scale[j][jhat-1] = wcsutil_dpkey_double(keyp);
d765 3
a767 3
    for (jhat = 0; jhat < Nhat; jhat++) {
      if (dis->axmap[j][jhat] == 0) {
        dis->axmap[j][jhat] = jhat;
d773 2
a774 2
    for (jhat = 0; jhat < naxis; jhat++) {
      if (dis->axmap[j][jhat] != 0) Nhat = jhat+1;
d784 3
a786 3
    for (jhat = 0; jhat < Nhat; jhat++) {
      for (k = 0; k < jhat; k++) {
        if (dis->axmap[j][jhat] == dis->axmap[j][k]) {
d809 1
d811 4
a814 4
    if (strcmp(dis->dtype[j], "TPV") == 0) {
      /* TPV "projection". */
      if ((status = tpvset(j, dis))) {
        /* (Preserve the error message set by tpvset().) */
d818 4
a821 4
    } else if (strcmp(dis->dtype[j], "Polynomial") == 0) {
      /* General polynomial distortion. */
      if ((status = polyset(j, dis))) {
        /* (Preserve the error message set by polyset().) */
d849 2
a850 2
  int axisj, j, jhat, naxis, Nhat, status;
  double dtmp, *offset, *scale, *tmpcrd;
a867 3
    offset = dis->offset[j];
    scale  = dis->scale[j];

d870 1
a870 1
      for (jhat = 0; jhat < Nhat; jhat++) {
d872 2
a873 2
        axisj = dis->axmap[j][jhat] - 1;
        tmpcrd[jhat] = (rawcrd[axisj] - offset[jhat])*scale[jhat];
d1130 1
a1130 1
      /* (Preserve the error message set by disp2x().) */
d1145 1
a1145 3
      if (maxdis && (dpix = fabs(dpix)) > maxdis[j]) {
        maxdis[j] = dpix;
      }
d1154 1
a1154 3
    if (maxtot && *maxtot < totdis) {
      *maxtot = totdis;
    }
d1495 1
a1495 1
  /* No specialist de-distortions. */
a1700 3
  /* No specialist de-distortions. */
  dis->disx2p[j] = 0x0;

d1727 4
@


5.2.1.4
log
@Fixed discpy() for change in length of disprm::dtype.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.2.1.3 2015/04/21 01:42:58 mcalabre Exp mcalabre $
d267 1
a267 1
  memcpy(disdst->dtype, dissrc->dtype, naxis*sizeof(char [72]));
@


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: dis.c,v 5.0.1.2 2015/04/07 08:45:17 mcalabre Exp mcalabre $
d40 3
d57 46
a107 1
  int j;
d120 1
a120 1
  /* Initialize memory management. */
d123 20
a142 18
      dis->disp2x  = 0x0;
      dis->disx2p  = 0x0;
      dis->tmpmem  = 0x0;
      dis->iwrk    = 0x0;
      dis->dwrk    = 0x0;
    }

    dis->m_flag    = 0;
    dis->m_naxis   = 0;
    dis->m_dtype   = 0x0;
    dis->m_axmap   = 0x0;
    dis->m_offset  = 0x0;
    dis->m_scale   = 0x0;
    dis->m_nparm   = 0x0;
    dis->m_parms   = 0x0;
    dis->m_maxdis  = 0x0;
    dis->m_alloc   = 0;
    dis->m_padding = 0;
a150 23
  /* Create work arrays. */
  if (dis->disp2x) free(dis->disp2x);
  if ((dis->disp2x = calloc(naxis, sizeof(int (*)(DISP2X_ARGS)))) == 0x0) {
    disfree(dis);
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  if (dis->disx2p) free(dis->disx2p);
  if ((dis->disx2p = calloc(naxis, sizeof(int (*)(DISX2P_ARGS)))) == 0x0) {
    disfree(dis);
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  if (dis->tmpmem) free(dis->tmpmem);
  if ((dis->tmpmem = calloc(5*naxis, sizeof(double))) == 0x0) {
    disfree(dis);
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  if (dis->iwrk) free(dis->iwrk);
  if (dis->dwrk) free(dis->dwrk);


d154 1
a154 5
      dis->axmap  == 0x0 ||
      dis->offset == 0x0 ||
      dis->scale  == 0x0 ||
      dis->nparm  == 0x0 ||
      dis->parms  == 0x0 ||
d158 3
a160 1
    if (dis->m_flag == DISSET && dis->m_naxis < naxis) {
d182 2
a183 2
    if (alloc || dis->axmap == 0x0) {
      if (dis->m_axmap) {
d185 1
a185 1
        dis->axmap = dis->m_axmap;
d188 7
a194 81
        if ((dis->axmap = calloc(naxis, sizeof(int *))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        if ((dis->axmap[0] = calloc(naxis*naxis, sizeof(int))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        for (j = 1; j < naxis; j++) {
          dis->axmap[j] = dis->axmap[j-1] + naxis;
        }

        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_axmap = dis->axmap;
      }
    }

    if (alloc || dis->offset == 0x0) {
      if (dis->m_offset) {
        /* In case the caller fiddled with it. */
        dis->offset = dis->m_offset;

      } else {
        if ((dis->offset = calloc(naxis, sizeof(double *))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        if ((dis->offset[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        for (j = 1; j < naxis; j++) {
          dis->offset[j] = dis->offset[j-1] + naxis;
        }

        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_offset = dis->offset;
      }
    }

    if (alloc || dis->scale == 0x0) {
      if (dis->m_scale) {
        /* In case the caller fiddled with it. */
        dis->scale = dis->m_scale;

      } else {
        if ((dis->scale = calloc(naxis, sizeof(double *))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        if ((dis->scale[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }

        for (j = 1; j < naxis; j++) {
          dis->scale[j] = dis->scale[j-1] + naxis;
        }

        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_scale = dis->scale;
      }
    }

    if (alloc || dis->nparm == 0x0) {
      if (dis->m_nparm) {
        /* In case the caller fiddled with it. */
        dis->nparm = dis->m_nparm;

      } else {
        if ((dis->nparm = calloc(naxis, sizeof(int))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d197 1
a197 16
        dis->m_flag  = DISSET;
        dis->m_naxis = naxis;
        dis->m_nparm = dis->nparm;
      }
    }

    if (alloc || dis->parms == 0x0) {
      if (dis->m_parms) {
        /* In case the caller fiddled with it. */
        dis->parms = dis->m_parms;

      } else {
        if ((dis->parms = calloc(naxis, sizeof(double *))) == 0x0) {
          disfree(dis);
          return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
        }
d201 1
a201 1
        dis->m_parms = dis->parms;
a222 2
  dis->m_alloc = 0;

d228 4
a231 11
  memset(dis->dtype,     0, naxis*sizeof(char [16]));
  memset(dis->axmap[0],  0, naxis*naxis*sizeof(int));
  memset(dis->offset[0], 0, naxis*naxis*sizeof(double));

  for (j = 0; j < naxis*naxis; j++) {
    dis->scale[0][j] = 1.0;
  }

  memset(dis->nparm,     0, naxis*sizeof(int));
  memset(dis->parms,     0, naxis*sizeof(double *));
  memset(dis->maxdis,    0, naxis*sizeof(double));
a233 42
  dis->ndis = 0;
  dis->padding = 0;

  return 0;
}

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

int disparms(struct disprm *dis)

{
  static const char *function = "disparms";

  int j;
  struct wcserr **err;

  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);


  /* Free memory previously allocated. */
  if (dis->m_alloc) {
    for (j = 0; j < dis->naxis; j++) {
      if (dis->parms[j]) {
        free(dis->parms[j]);
        dis->parms[j] = 0x0;
      }
    }
  }

  /* Allocate memory for distortion parameter arrays. */
  for (j = 0; j < dis->naxis; j++) {
    if (dis->nparm[j]) {
      if ((dis->parms[j] = calloc(dis->nparm[j], sizeof(double))) == 0x0) {
        return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
      }

      dis->m_flag  = DISSET;
      dis->m_alloc = 1;
    }
  }

d245 1
a245 1
  int j, naxis, status;
d258 3
d265 2
a267 10
  for (j = 0; j < naxis; j++) {
    memcpy(disdst->axmap[j],  dissrc->axmap[j],  naxis*sizeof(int));
    memcpy(disdst->offset[j], dissrc->offset[j], naxis*sizeof(double));
    memcpy(disdst->scale[j],  dissrc->scale[j],  naxis*sizeof(double));
  }
  memcpy(disdst->nparm, dissrc->nparm, naxis*sizeof(int));

  if (alloc) {
    disparms(disdst);
  }
d269 3
a271 6
  for (j = 0; j < naxis; j++) {
    if (dissrc->nparm[j]) {
      memcpy(disdst->parms[j], dissrc->parms[j],
             dissrc->nparm[j]*sizeof(double));
    }
  }
d289 1
a289 1
    /* Free memory allocated by disini(). */
a290 14
      /* Recall that these were allocated in bulk. */
      if (dis->m_axmap)  free(dis->axmap[0]);
      if (dis->m_offset) free(dis->offset[0]);
      if (dis->m_scale)  free(dis->scale[0]);

      if (dis->m_alloc) {
        for (j = 0; j < dis->naxis; j++) {
          if (dis->parms[j]) {
            free(dis->parms[j]);
            dis->parms[j] = 0x0;
          }
        }
      }

d292 1
a292 5
      if (dis->axmap  == dis->m_axmap)  dis->axmap  = 0x0;
      if (dis->offset == dis->m_offset) dis->offset = 0x0;
      if (dis->scale  == dis->m_scale)  dis->scale  = 0x0;
      if (dis->nparm  == dis->m_nparm)  dis->nparm  = 0x0;
      if (dis->parms  == dis->m_parms)  dis->parms  = 0x0;
a294 6
      if (dis->disp2x) free(dis->disp2x);
      if (dis->disx2p) free(dis->disx2p);
      if (dis->tmpmem) free(dis->tmpmem);
      if (dis->iwrk)   free(dis->iwrk);
      if (dis->dwrk)   free(dis->dwrk);

d296 1
a296 5
      if (dis->m_axmap)  free(dis->m_axmap);
      if (dis->m_offset) free(dis->m_offset);
      if (dis->m_scale)  free(dis->m_scale);
      if (dis->m_nparm)  free(dis->m_nparm);
      if (dis->m_parms)  free(dis->m_parms);
d299 22
a322 6
  dis->disp2x  = 0x0;
  dis->disx2p  = 0x0;
  dis->tmpmem  = 0x0;
  dis->iwrk    = 0x0;
  dis->dwrk    = 0x0;

d326 1
a326 5
  dis->m_axmap  = 0x0;
  dis->m_offset = 0x0;
  dis->m_scale  = 0x0;
  dis->m_nparm  = 0x0;
  dis->m_parms  = 0x0;
d328 12
a339 1
  dis->m_alloc  = 0;
a342 5
  if (dis->err) {
    free(dis->err);
    dis->err = 0x0;
  }

d370 23
d402 7
d427 1
a427 2
  WCSPRINTF_PTR("      nparm: ", dis->nparm, "\n");
  wcsprintf("            ");
d429 8
a436 1
    wcsprintf("%6d", dis->nparm[j]);
a437 1
  wcsprintf("\n");
d439 1
a439 1
  WCSPRINTF_PTR("      parms: ", dis->parms, "\n");
d441 2
a442 2
    wcsprintf(" parms[%d][]:", j);
    for (k = 0; k < dis->nparm[j]; k++) {
d446 1
a446 1
      wcsprintf("  %#- 11.5g", dis->parms[j][k]);
d451 1
a451 10
  WCSPRINTF_PTR("     maxdis: ", dis->maxdis, "\n");
  wcsprintf("            ");
  for (j = 0; j < dis->naxis; j++) {
    wcsprintf("  %#- 11.5g", dis->maxdis[j]);
  }
  wcsprintf("\n");

  wcsprintf("     totdis:  %#- 11.5g\n", dis->totdis);

  /* Derived values. */
a488 2
  WCSPRINTF_PTR("       iwrk: ", dis->iwrk, "\n");
  WCSPRINTF_PTR("       dwrk: ", dis->dwrk, "\n");
d496 2
a497 14
  WCSPRINTF_PTR("    m_axmap: ", dis->m_axmap, "");
  if (dis->m_axmap  == dis->axmap)  wcsprintf("  (= axmap)");
  wcsprintf("\n");
  WCSPRINTF_PTR("   m_offset: ", dis->m_offset, "");
  if (dis->m_offset == dis->offset) wcsprintf("  (= offset)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_scale: ", dis->m_scale, "");
  if (dis->m_scale  == dis->scale)  wcsprintf("  (= scale)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_nparm: ", dis->m_nparm, "");
  if (dis->m_nparm  == dis->nparm)  wcsprintf("  (= nparm)");
  wcsprintf("\n");
  WCSPRINTF_PTR("    m_parms: ", dis->m_parms, "");
  if (dis->m_parms  == dis->parms)  wcsprintf("  (= parms)");
d513 3
a515 1
  int j, naxis, ndis, status;
d523 210
d739 15
d758 2
a759 1
        return wcserr_set(DIS_ERRMSG(status));
d764 1
a764 1
        "Unrecognized/unimplemented distortion function, %s", dis->dtype[j]);
d786 1
a786 1
  int axisi, i, j, naxis, ncrd, status;
d806 5
a810 9
      ncrd = 0;
      for (i = 0; i < naxis; i++) {
        if ((axisi = dis->axmap[j][i])) {
          /* N.B. the axis numbers in the map are 1-relative. */
          tmpcrd[i] = (rawcrd[axisi-1] - dis->offset[j][i])*dis->scale[j][i];
          ncrd++;
        } else {
          tmpcrd[i] = 0.0;
        }
d813 1
a813 1
      if ((status = (dis->disp2x[j])(dis->nparm[j], dis->parms[j], ncrd,
d1087 1
a1090 1
    totdis = sqrt(dssq);
d1129 427
d1561 3
a1563 1
  int i, nparm;
d1569 2
d1573 1
a1573 1
  if (dis->axmap[j][0] == 0) {
d1575 1
a1575 1
      "Invalid axis 1 mapping for TPV on axis %d", j);
d1578 21
a1598 4
  if (dis->axmap[j][1] == 0 || dis->axmap[j][1] == dis->axmap[j][0]) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Invalid axis 2 mapping for TPV on axis %d", j);
  }
d1600 4
a1603 2
  for (i = 2; i < dis->naxis; i++) {
    if (dis->axmap[j][i]) {
d1605 1
a1605 1
        "Invalid axis map for TPV on axis %d, more than two entries", j);
d1609 1
a1609 3
  /* Determine the degree of the polynomial. */
  nparm = dis->nparm[j];
  if (nparm == 4) {
d1611 1
d1613 1
a1613 1
  } else if (nparm == 7) {
d1615 1
d1617 1
a1617 1
  } else if (nparm == 12) {
d1619 1
d1621 1
a1621 1
  } else if (nparm == 17) {
d1623 1
d1625 1
a1625 1
  } else if (nparm == 24) {
d1627 1
d1629 1
a1629 1
  } else if (nparm == 31) {
d1631 1
d1633 1
a1633 1
  } else if (nparm == 40) {
d1635 1
d1639 16
a1654 1
      "Invalid number of parameters (%d) for TPV on axis %d", nparm, j);
d1657 10
d1676 1
a1676 1
  int nparm,
d1678 1
a1678 1
  int ncrd,
d1685 1
a1685 1
  if (nparm != 4 || ncrd != 2) {
d1703 1
a1703 1
  int nparm,
d1705 1
a1705 1
  int ncrd,
d1712 1
a1712 1
  if (nparm != 7 || ncrd != 2) {
d1734 1
a1734 1
  int nparm,
d1736 1
a1736 1
  int ncrd,
d1743 1
a1743 1
  if (nparm != 12 || ncrd != 2) {
d1766 1
a1766 1
  int nparm,
d1768 1
a1768 1
  int ncrd,
d1775 1
a1775 1
  if (nparm != 17 || ncrd != 2) {
d1799 1
a1799 1
  int nparm,
d1801 1
a1801 1
  int ncrd,
d1808 1
a1808 1
  if (nparm != 24 || ncrd != 2) {
d1833 1
a1833 1
  int nparm,
d1835 1
a1835 1
  int ncrd,
d1842 1
a1842 1
  if (nparm != 31 || ncrd != 2) {
d1868 1
a1868 1
  int nparm,
d1870 1
a1870 1
  int ncrd,
d1877 1
a1877 1
  if (nparm != 40 || ncrd != 2) {
@


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


5.1.1.2
log
@Bug fix in diswarp().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.1 2015/04/07 11:01:10 mcalabre Exp mcalabre $
a983 1
    totdis = sqrt(dssq);
d987 1
@


5.1.1.3
log
@Significant development to support Paper IV, including changes to the disprm
struct, removal of disparms(), addition of the dpkey struct and dpfill(),
and the implementation of the Polynomial distortion function.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.2 2015/04/07 23:28:21 mcalabre Exp mcalabre $
a39 3
/* Maximum number of DPja or DQia keywords. */
int NDPMAX = 256;

a53 4
int disndp(int ndpmax) { if (ndpmax >= 0) NDPMAX = ndpmax; return NDPMAX; }

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

d72 1
a72 1
  /* Initialize pointers. */
d75 18
a92 20
      dis->axmap  = 0x0;
      dis->Nhat   = 0x0;
      dis->offset = 0x0;
      dis->scale  = 0x0;
      dis->iparm  = 0x0;
      dis->dparm  = 0x0;

      dis->disp2x = 0x0;
      dis->disx2p = 0x0;
      dis->tmpmem = 0x0;

      dis->i_naxis = 0;
    }

    /* Initialize memory management. */
    dis->m_flag   = 0;
    dis->m_naxis  = 0;
    dis->m_dtype  = 0x0;
    dis->m_dp     = 0x0;
    dis->m_maxdis = 0x0;
d101 23
d127 5
a131 1
      (NDPMAX && dis->dp == 0x0) ||
d135 1
a135 3
    if (dis->m_flag == DISSET &&
       (dis->m_naxis < naxis  ||
        dis->ndpmax  < NDPMAX)) {
d157 2
a158 2
    if (alloc || dis->dp == 0x0) {
      if (dis->m_dp) {
d160 1
a160 1
        dis->dp = dis->m_dp;
d163 3
a165 7
        if (NDPMAX) {
          if ((dis->dp = calloc(NDPMAX, sizeof(struct dpkey))) == 0x0) {
            disfree(dis);
            return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
          }
        } else {
          dis->dp = 0x0;
d168 8
a175 1
        dis->ndpmax  = NDPMAX;
d179 1
a179 1
        dis->m_dp    = dis->dp;
d183 2
a184 2
    if (alloc || dis->maxdis == 0x0) {
      if (dis->m_maxdis) {
d186 1
a186 1
        dis->maxdis = dis->m_maxdis;
d189 6
a194 1
        if ((dis->maxdis = calloc(naxis, sizeof(double))) == 0x0) {
d199 4
d205 1
a205 1
        dis->m_maxdis = dis->maxdis;
a207 1
  }
d209 4
d214 5
a218 19
  /* Allocate memory for derived parameters and work arrays. */
  if (dis->i_naxis < naxis) {
    if (dis->i_naxis) {
      /* Recall that axmap, offset, and scale are allocated in bulk. */
      free(dis->axmap[0]);
      free(dis->axmap);
      free(dis->Nhat);
      free(dis->offset[0]);
      free(dis->offset);
      free(dis->scale[0]);
      free(dis->scale);

      for (j = 0; j < dis->i_naxis; j++) {
        /* Memory allocated by disset() separately for each axis. */
        if (dis->iparm[j]) free(dis->iparm[j]);
        if (dis->dparm[j]) free(dis->dparm[j]);
      }
      free(dis->iparm);
      free(dis->dparm);
d220 4
a223 2
      free(dis->disp2x);
      free(dis->disx2p);
d225 3
a227 2
      free(dis->tmpmem);
    }
d229 4
a232 3
    if ((dis->axmap = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d235 4
a238 4
    if ((dis->axmap[0] = calloc(naxis*naxis, sizeof(int))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
d240 5
a244 4
    if ((dis->Nhat = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
d246 4
a249 3
    if ((dis->offset = calloc(naxis, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d252 4
a255 4
    if ((dis->offset[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
d257 5
a261 4
    if ((dis->scale = calloc(naxis, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
d263 4
a266 3
    if ((dis->scale[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d269 4
a272 4
    if ((dis->iparm = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
d274 5
a278 4
    if ((dis->dparm = calloc(naxis, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
d280 4
a283 10
    /* Carve up the 2D arrays. */
    for (j = 1; j < naxis; j++) {
      dis->axmap[j]  = dis->axmap[j-1]  + naxis;
      dis->offset[j] = dis->offset[j-1] + naxis;
      dis->scale[j]  = dis->scale[j-1]  + naxis;
    }

    if ((dis->disp2x = calloc(naxis, sizeof(int (*)(DISP2X_ARGS)))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
d285 1
d287 1
a287 12
    if ((dis->disx2p = calloc(naxis, sizeof(int (*)(DISX2P_ARGS)))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->tmpmem = calloc(5*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    dis->i_naxis = naxis;
  }
d294 1
a294 8
  memset(dis->dtype,  0, naxis*sizeof(char [16]));
  dis->ndp = 0;
  memset(dis->dp,     0, NDPMAX*sizeof(struct dpkey));
  memset(dis->maxdis, 0, naxis*sizeof(double));
  dis->totdis = 0.0;


  /* Ensure that disset() starts with a clean slate. */
a295 1
  memset(dis->Nhat,      0, naxis*sizeof(int));
d302 5
d308 1
a308 5

  /* (disset() must look after iparm and dparm.) */
  memset(dis->disp2x, 0, naxis*sizeof(int (*)(DISP2X_ARGS)));
  memset(dis->disx2p, 0, naxis*sizeof(int (*)(DISX2P_ARGS)));
  memset(dis->tmpmem, 0, naxis*sizeof(double));
d315 1
a315 8
int dpfill(
  struct dpkey *dp,
  const char *keyword,
  const char *field,
  int j,
  int type,
  int ival,
  double fval)
d318 1
a318 1
  char *cp;
d320 14
a333 5
  if (keyword) {
    if (field) {
      sprintf(dp->field, "%s.%s", keyword, field);
    } else {
      strcpy(dp->field, keyword);
a334 2
  } else if (field) {
    strcpy(dp->field, field);
d337 9
a345 6
  if (j) {
    dp->j = j;
  } else {
    /* The field name must either be given or preset. */
    if ((cp = strpbrk(dp->field, "0123456789")) != 0x0) {
      sscanf(cp, "%d.", &(dp->j));
a348 6
  if ((dp->type = type)) {
    dp->value.f = fval;
  } else {
    dp->value.i = ival;
  }

d360 1
a360 1
  int naxis, ndp, status;
a372 3
  ndp = NDPMAX;
  NDPMAX = dissrc->ndpmax;

a376 2
  NDPMAX = ndp;

d378 6
d385 10
a394 3
  disdst->ndp = dissrc->ndp;
  disdst->ndpmax = dissrc->ndpmax;
  memcpy(disdst->dp, dissrc->dp, dissrc->ndpmax*sizeof(struct dpkey));
d412 1
a412 1
    /* Optionally allocated by disini() for given parameters. */
d414 14
d429 5
a433 1
      if (dis->dp     == dis->m_dp)     dis->dp     = 0x0;
d436 6
d443 5
a447 1
      if (dis->m_dp)     free(dis->m_dp);
d450 1
d452 5
a456 22
    /* Recall that these were allocated in bulk by disini(). */
    if (dis->axmap  && dis->axmap[0])  free(dis->axmap[0]);
    if (dis->offset && dis->offset[0]) free(dis->offset[0]);
    if (dis->scale  && dis->scale[0])  free(dis->scale[0]);

    if (dis->axmap)  free(dis->axmap);
    if (dis->Nhat)   free(dis->Nhat);
    if (dis->offset) free(dis->offset);
    if (dis->scale)  free(dis->scale);
    for (j = 0; j < dis->i_naxis; j++) {
      if (dis->iparm[j]) free(dis->iparm[j]);
      if (dis->dparm[j]) free(dis->dparm[j]);
    }
    if (dis->iparm)  free(dis->iparm);
    if (dis->dparm)  free(dis->dparm);

    if (dis->disp2x) free(dis->disp2x);
    if (dis->disx2p) free(dis->disx2p);
    if (dis->tmpmem) free(dis->tmpmem);

    if (dis->err) free(dis->err);
  }
d461 5
a465 1
  dis->m_dp     = 0x0;
d467 1
d469 1
a469 9
  dis->axmap  = 0x0;
  dis->Nhat   = 0x0;
  dis->offset = 0x0;
  dis->scale  = 0x0;
  dis->iparm  = 0x0;
  dis->dparm  = 0x0;
  dis->disp2x = 0x0;
  dis->disx2p = 0x0;
  dis->tmpmem = 0x0;
d471 4
a474 3
  dis->err  = 0x0;

  dis->flag = 0;
a502 23
  wcsprintf("        ndp: %d\n", dis->ndp);
  wcsprintf("     ndpmax: %d\n", dis->ndpmax);
  WCSPRINTF_PTR("         dp: ", dis->dp, "\n");
  for (i = 0; i < dis->ndp; i++) {
    if (dis->dp[i].type) {
      wcsprintf("             %3d%3d  %#- 11.5g  %.32s\n",
        dis->dp[i].j, dis->dp[i].type, dis->dp[i].value.f, dis->dp[i].field);
    } else {
      wcsprintf("             %3d%3d  %11d  %.32s\n",
        dis->dp[i].j, dis->dp[i].type, dis->dp[i].value.i, dis->dp[i].field);
    }
  }

  WCSPRINTF_PTR("     maxdis: ", dis->maxdis, "\n");
  wcsprintf("            ");
  for (j = 0; j < dis->naxis; j++) {
    wcsprintf("  %#- 11.5g", dis->maxdis[j]);
  }
  wcsprintf("\n");

  wcsprintf("     totdis:  %#- 11.5g\n", dis->totdis);

  /* Derived values. */
a511 7
  WCSPRINTF_PTR("       Nhat: ", dis->Nhat, "\n");
  wcsprintf("            ");
  for (j = 0; j < dis->naxis; j++) {
    wcsprintf("%6d", dis->Nhat[j]);
  }
  wcsprintf("\n");

d530 8
a537 1
  WCSPRINTF_PTR("      iparm: ", dis->iparm, "\n");
d539 2
a540 2
    wcsprintf(" iparm[%d][]:", j);
    for (k = 0; k < dis->iparm[j][0]; k++) {
d544 1
a544 1
      wcsprintf("  %11d", dis->iparm[j][k]);
d549 2
a550 1
  WCSPRINTF_PTR("      dparm: ", dis->dparm, "\n");
d552 1
a552 8
    wcsprintf(" dparm[%d][]:", j);
    for (k = 0; k < dis->iparm[j][1]; k++) {
      if (k && k%5 == 0) {
        wcsprintf("\n            ");
      }
      wcsprintf("  %#- 11.5g", dis->dparm[j][k]);
    }
    wcsprintf("\n");
d554 3
d558 1
a558 1
  wcsprintf("    i_naxis: %d\n", dis->i_naxis);
d596 2
d605 14
a618 2
  WCSPRINTF_PTR("       m_dp: ", dis->m_dp, "");
  if (dis->m_dp     == dis->dp)     wcsprintf("  (= dp)");
d634 1
a634 3
  char   *fp;
  int    i, idp, j, k, naxis, ndis, Nhat, status;
  struct dpkey *keyp;
a641 80

  /* Handle DPja or DQia keywords common to all distortions. */
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    j = keyp->j;

    if (j < 1 || naxis < j) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid axis number (%d) in %s", j, keyp->field);
    }

    if ((fp = strpbrk(keyp->field, ".")) == 0x0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid record field name: %s", j, keyp->field);
    }
    fp++;

    j--;
    if (strncmp(fp, "NAXES", 6) == 0) {
      Nhat = keyp->value.i;
      if (Nhat < 0 || naxis < Nhat) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid value of Nhat for %s distortion in %s: %d", dis->dtype[j],
          keyp->field, Nhat);
      }

      dis->Nhat[j] = Nhat;

    } else if (strncmp(fp, "AXIS.", 5) == 0) {
      sscanf(fp+5, "%d", &i);
      if (i < 0 || naxis < i) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid axis in axis map for %s distortion in %s: %d",
          dis->dtype[j], keyp->field, i);
      }

      dis->axmap[j][i-1] = keyp->value.i;

    } else if (strncmp(fp, "OFFSET.", 7) == 0) {
      sscanf(fp+7, "%d", &i);
      dis->offset[j][i-1] = keyp->value.f;

    } else if (strncmp(fp, "SCALE.", 6) == 0) {
      sscanf(fp+6, "%d", &i);
      dis->scale[j][i-1] = keyp->value.f;
    }
  }

  /* Sanity check on the axis maps. */
  for (j = 0; j < naxis; j++) {
    Nhat = 0;
    for (i = 0; i < naxis; i++) {
      if (dis->axmap[j][i] != 0) Nhat = i+1;
    }

    if (Nhat != dis->Nhat[j]) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Mismatch in length of axis map for %s distortion on axis %d",
        dis->dtype[j], j+1);
    }

    for (i = 0; i < Nhat; i++) {
      if (dis->axmap[j][i] == 0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid axis map for %s distortion on axis %d", dis->dtype[j],
          j+1);
      }

      /* Check uniqueness. */
      for (k = 0; k < i; k++) {
        if (dis->axmap[j][i] == dis->axmap[j][k]) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
            "Duplicated entry in axis map for %s distortion on axis %d",
            dis->dtype[j], j+1);
        }
      }
    }
  }


a647 15
    }

    if (dis->Nhat[j] == 0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Empty axis map for %s distortion on axis %d", dis->dtype[j], j+1);
    }


    /* Invoke the specific setup functions for each distortion. */
    if (strcmp(dis->dtype[j], "Polynomial") == 0) {
      /* General polynomial distortion. */
      if ((status = polyset(j, dis))) {
        /* (Preserve the error message set by polyset().) */
        return status;
      }
d652 1
a652 2
        /* (Preserve the error message set by tpvset().) */
        return status;
d657 1
a657 1
        "Unrecognized/unimplemented distortion function: %s", dis->dtype[j]);
d679 1
a679 1
  int axisi, i, j, naxis, Nhat, status;
d699 9
a707 5
      Nhat = dis->Nhat[j];
      for (i = 0; i < Nhat; i++) {
        /* N.B. the axis numbers in the map are 1-relative. */
        axisi = dis->axmap[j][i] - 1;
        tmpcrd[i] = (rawcrd[axisi] - dis->offset[j][i])*dis->scale[j][i];
d710 1
a710 1
      if ((status = (dis->disp2x[j])(dis->iparm[j], dis->dparm[j], Nhat,
a1025 282
int polyset(int j, struct disprm *dis)

{
  static const char *function = "polyset";

  char   *fp, id[32];
  int    i, idp, jhat, k, K, m, M, naxis, Nhat, nKparm, nparm, ntot, nTparm,
         offset;
  double *pptr;
  struct dpkey *keyp;
  struct wcserr **err;


  /* Initialize. */
  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  naxis = dis->naxis;
  sprintf(id, "Polynomial on axis %d", j+1);


  /* Find the number of auxiliary variables and terms. */
  K = 0;
  M = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    if ((fp = strpbrk(keyp->field, ".")) == 0x0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid field name for %s: %s", id, keyp->field);
    }
    fp++;

    if (strcmp(fp, "NAUX") == 0) {
      K = keyp->value.i;
    } else if (strcmp(fp, "NTERMS") == 0) {
      M = keyp->value.i;
    }
  }

  if (K < 0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Invalid number of auxiliaries (%d) for %s", K, id);
  }

  if (M <= 0) {
    return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
      "Invalid number of terms (%d) for %s", M, id);
  }

  Nhat = dis->Nhat[j];
  nKparm = 2*(Nhat + 1);
  nTparm = 1 + Nhat + K;
  nparm  = K*nKparm + M*nTparm;

  /* Record indexing parameters. */
  if ((dis->iparm[j] = calloc(7, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* Add extra memory for temporaries. */
  ntot = nparm + K;

  dis->iparm[j][0] = 6;
  dis->iparm[j][1] = nparm;
  dis->iparm[j][2] = ntot;
  dis->iparm[j][3] = K;
  dis->iparm[j][4] = M;
  dis->iparm[j][5] = nKparm;
  dis->iparm[j][6] = nTparm;


  /* Allocate memory for the parameter array and fill it. */
  if ((dis->dparm[j] = calloc(ntot, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  /* Set default values of POWER for the auxiliary variables. */
  pptr = dis->dparm[j] + (1 + Nhat);
  for (k = 0; k < K; k++) {
    for (jhat = 0; jhat <= Nhat; jhat++) {
      pptr[jhat] = 1.0;
    }
    pptr += nKparm;
  }

  /* Set default values of COEFF for the independent variables. */
  pptr = dis->dparm[j] + K*nKparm;
  for (m = 0; m < M; m++) {
    *pptr = 1.0;
    pptr += nTparm;
  }

  /* Extract parameter values from DPja or DQia. */
  k = m = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    /* N.B. keyp->j is 1-relative, but j is 0-relative. */
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".") + 1;

    if (strncmp(fp, "AUX.", 4) == 0) {
      /* N.B. k here is 1-relative. */
      fp += 4;
      sscanf(fp, "%d", &k);
      if (k < 1 || K < k) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
      }

      if ((fp = strpbrk(fp, ".")) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      if (strncmp(fp, "COEFF.", 6) == 0) {
        offset = 0;

      } else if (strncmp(fp, "POWER.", 6) == 0) {
        offset = 1 + Nhat;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

      fp += 6;
      sscanf(fp, "%d", &jhat);
      if (jhat < 0 || naxis < jhat) {
        /* N.B. jhat == 0 is ok. */
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid axis number (%d) for %s: %s", jhat, id, keyp->field);
      }

      i = (k-1)*nKparm + offset + jhat;
      dis->dparm[j][i] = keyp->value.f;

    } else if (strncmp(fp, "TERM.", 5) == 0) {
      /* N.B. m here is 1-relative. */
      fp += 5;
      sscanf(fp, "%d", &m);
      if (m < 1 || M < m) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Bad term (%d) for %s: %s", m, id, keyp->field);
      }

      if ((fp = strpbrk(fp, ".")) == 0x0) {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid field name for %s: %s", id, keyp->field);
      }
      fp++;

      if (strcmp(fp, "COEFF") == 0) {
        i = K*nKparm + (m-1)*nTparm;
        dis->dparm[j][i] = keyp->value.f;

      } else if (strncmp(fp, "VAR.", 4) == 0) {
        /* N.B. jhat here is 1-relative. */
        fp += 4;
        sscanf(fp, "%d", &jhat);
        if (jhat < 1 || naxis < jhat) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid axis number (%d) for %s: %s", jhat, id, keyp->field);
        }

        i = K*nKparm + (m-1)*nTparm + 1 + (jhat-1);
        dis->dparm[j][i] = keyp->value.f;

      } else if (strncmp(fp, "AUX.", 4) == 0) {
        /* N.B. k here is 1-relative. */
        fp += 4;
        sscanf(fp, "%d", &k);
        if (k < 1 || K < k) {
          return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
            "Bad auxiliary variable (%d) for %s: %s", k, id, keyp->field);
        }

        i = K*nKparm + (m-1)*nTparm + 1 + Nhat + (k-1);
        dis->dparm[j][i] = keyp->value.f;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Unrecognized field name for %s: %s", id, keyp->field);
      }

    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6) &&
               strcmp(fp, "NAUX")   &&
               strcmp(fp, "NTERMS")) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Unrecognized field name for %s: %s", id, keyp->field);
    }
  }

  /* No specialist deprojections. */
  dis->disp2x[j] = dispoly;
  dis->disx2p[j] = 0x0;

  return 0;
}

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

int dispoly(
  const int ip[],
  const double p[],
  int Nhat,
  const double rawcrd[],
  double *discrd)

{
  int    jhat, k, K, m, M, nKparm, nparm;
  const double *cptr, *pptr;
  double *aux, auxp0, term;

  nparm  = ip[1];
  K      = ip[3];
  M      = ip[4];
  nKparm = ip[5];

  /* Check for zeroes. */
  for (jhat = 0; jhat < Nhat; jhat++) {
    if (rawcrd[jhat] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }

  /* Working memory was allocated at the end of p[]. */
  aux = (double *)(p + nparm);

  /* Compute the auxiliary variables. */
  for (k = 0; k < K; k++) {
    cptr = p + k*nKparm;
    pptr = cptr + (1+Nhat);

    aux[k] = *(cptr++);
    auxp0  = *(pptr++);

    for (jhat = 0; jhat < Nhat; jhat++) {
      aux[k] += *(cptr++)*pow(rawcrd[jhat], *(pptr++));
    }

    aux[k] = pow(aux[k], auxp0);

    /* Check for zeroes. */
    if (aux[k] == 0.0) {
      *discrd = 0.0;
      return 0;
    }
  }

  /* Loop for each term of the polynomial. */
  *discrd = 0.0;
  pptr = p + K*nKparm;
  for (m = 0; m < M; m++) {
    term = *(pptr++);

    /* Loop over the independent variables. */
    for (jhat = 0; jhat < Nhat; jhat++) {
      term *= pow(rawcrd[jhat], *(pptr++));
    }

    /* Loop over the auxiliary variables. */
    for (k = 0; k < K; k++) {
      term *= pow(aux[k], *(pptr++));
    }

    *discrd += term;
  }

  return 0;
}


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

d1031 1
a1031 3
  char   *fp, id[16];
  int    idp, k, nparm;
  struct dpkey *keyp;
a1036 2
  sprintf(id, "TPV on axis %d", j+1);

d1039 1
a1039 1
  if (dis->Nhat[j] != 2) {
d1041 1
a1041 1
      "Axis map for %s must contain 2 entries, not %d", id, dis->Nhat[j]);
d1044 4
a1047 21
  /* Find the number of parameters. */
  nparm = 0;
  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    if ((fp = strpbrk(keyp->field, ".")) == 0x0) {
      return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
        "Invalid field name for %s: %s", id, keyp->field);
    }
    fp++;

    if (strncmp(fp, "TPV.", 4) == 0) {
      sscanf(fp+4, "%d", &k);
      if (0 <= k && k <= 39) {
        if (nparm < k+1) nparm = k+1;

      } else {
        return wcserr_set(WCSERR_SET(DISERR_BAD_PARAM),
          "Invalid parameter number (%d) for %s: %s", k, id, keyp->field);
      }
d1049 2
a1050 4
    } else if (strcmp(fp, "NAXES")  &&
              strncmp(fp, "AXIS.",   5) &&
              strncmp(fp, "OFFSET.", 7) &&
              strncmp(fp, "SCALE.",  6)) {
d1052 1
a1052 1
        "Unrecognized field name for %s: %s", id, keyp->field);
d1056 3
a1058 1
  if (nparm <= 4) {
a1059 1
    nparm = 4;
d1061 1
a1061 1
  } else if (nparm <= 7) {
a1062 1
    nparm = 7;
d1064 1
a1064 1
  } else if (nparm <= 12) {
a1065 1
    nparm = 12;
d1067 1
a1067 1
  } else if (nparm <= 17) {
a1068 1
    nparm = 17;
d1070 1
a1070 1
  } else if (nparm <= 24) {
a1071 1
    nparm = 24;
d1073 1
a1073 1
  } else if (nparm <= 31) {
a1074 1
    nparm = 31;
d1076 1
a1076 1
  } else if (nparm <= 40) {
a1077 1
    nparm = 40;
d1081 1
a1081 1
      "Invalid number of parameters (%d) for %s", nparm, id);
a1083 24
  /* Record indexing parameters. */
  if ((dis->iparm[j] = calloc(2, sizeof(int))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  dis->iparm[j][0] = 2;
  dis->iparm[j][1] = nparm;


  /* Allocate memory for the polynomial coefficients and fill it. */
  if ((dis->dparm[j] = calloc(nparm, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  keyp = dis->dp;
  for (idp = 0; idp < dis->ndp; idp++, keyp++) {
    if (keyp->j-1 != j) continue;

    fp = strpbrk(keyp->field, ".")+5;
    sscanf(fp, "%d:", &k);
    dis->dparm[j][k] = keyp->value.f;
  }


d1093 1
a1093 1
  const int i[],
d1095 1
a1095 1
  int Nhat,
d1102 1
a1102 1
  if (i[1] != 4 || Nhat != 2) {
d1120 1
a1120 1
  const int i[],
d1122 1
a1122 1
  int Nhat,
d1129 1
a1129 1
  if (i[1] != 7 || Nhat != 2) {
d1151 1
a1151 1
  const int i[],
d1153 1
a1153 1
  int Nhat,
d1160 1
a1160 1
  if (i[1] != 12 || Nhat != 2) {
d1183 1
a1183 1
  const int i[],
d1185 1
a1185 1
  int Nhat,
d1192 1
a1192 1
  if (i[1] != 17 || Nhat != 2) {
d1216 1
a1216 1
  const int i[],
d1218 1
a1218 1
  int Nhat,
d1225 1
a1225 1
  if (i[1] != 24 || Nhat != 2) {
d1250 1
a1250 1
  const int i[],
d1252 1
a1252 1
  int Nhat,
d1259 1
a1259 1
  if (i[1] != 31 || Nhat != 2) {
d1285 1
a1285 1
  const int i[],
d1287 1
a1287 1
  int Nhat,
d1294 1
a1294 1
  if (i[1] != 40 || Nhat != 2) {
@


5.1.1.4
log
@Changed the order of the functions.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.3 2015/04/13 08:32:43 mcalabre Exp mcalabre $
a60 42
int dpfill(
  struct dpkey *dp,
  const char *keyword,
  const char *field,
  int j,
  int type,
  int ival,
  double fval)

{
  char *cp;

  if (keyword) {
    if (field) {
      sprintf(dp->field, "%s.%s", keyword, field);
    } else {
      strcpy(dp->field, keyword);
    }
  } else if (field) {
    strcpy(dp->field, field);
  }

  if (j) {
    dp->j = j;
  } else {
    /* The field name must either be given or preset. */
    if ((cp = strpbrk(dp->field, "0123456789")) != 0x0) {
      sscanf(cp, "%d.", &(dp->j));
    }
  }

  if ((dp->type = type)) {
    dp->value.f = fval;
  } else {
    dp->value.i = ival;
  }

  return 0;
}

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

d306 42
@


5.1.1.5
log
@Small change to dispoly() yielding a 22% speedup.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.4 2015/04/13 09:35:41 mcalabre Exp $
d1378 2
a1379 4
    for (jhat = 0; jhat < Nhat; jhat++, pptr++) {
      if (*pptr != 0.0) {
        term *= pow(rawcrd[jhat], *pptr);
      }
d1383 2
a1384 4
    for (k = 0; k < K; k++, pptr++) {
      if (*pptr != 0.0) {
        term *= pow(aux[k], *pptr);
      }
@


5.1.1.6
log
@A more elaborate change to polyset() and dispoly() yielding a further speedup
of 70%.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.5 2015/04/13 13:23:46 mcalabre Exp mcalabre $
d1120 3
a1122 3
  int    i, idp, jhat, k, K, lenidx, lendp, m, M, naxis, ndparm, Nhat, niparm,
         nKparm, nTparm, nTpow, offset;
  double power, *pptr;
d1167 2
a1168 11
  nTpow  = Nhat + K;
  nTparm = 1 + nTpow;
  ndparm = K*nKparm + M*nTparm;

  /* Add extra for integer exponents.  When the power is integral, */
  /* it is faster to multiply repeatedly than call pow().          */
  lenidx = 10;
  niparm = lenidx + 2*M*nTpow;

  /* Add extra memory for temporaries. */
  lendp = ndparm + K;
d1171 1
a1171 1
  if ((dis->iparm[j] = calloc(niparm, sizeof(int))) == 0x0) {
d1175 10
a1184 11
  /* The first two are required by disprt(). */
  dis->iparm[j][0] = niparm;
  dis->iparm[j][1] = ndparm;
  dis->iparm[j][2] = lenidx;
  dis->iparm[j][3] = lendp;
  dis->iparm[j][4] = K;
  dis->iparm[j][5] = M;
  dis->iparm[j][6] = nKparm;
  dis->iparm[j][7] = nTparm;
  dis->iparm[j][8] = nTpow;
  dis->iparm[j][9] = M*nTpow;
d1188 1
a1188 1
  if ((dis->dparm[j] = calloc(lendp, sizeof(double))) == 0x0) {
d1283 1
a1283 10
        power = keyp->value.f;
        dis->dparm[j][i] = power;

        /* Is it integral? */
        if (floor(power) == ceil(power)) {
          i = lenidx + (m-1)*nTpow + (jhat-1);
          dis->iparm[j][i] = 1;
          i += M*nTpow;
          dis->iparm[j][i] = (int)power;
        }
d1295 1
a1295 10
        power = keyp->value.f;
        dis->dparm[j][i] = power;

        /* Is it integral? */
        if (floor(power) == ceil(power)) {
          i = lenidx + (m-1)*nTpow + Nhat + (k-1);
          dis->iparm[j][i] = 1;
          i += M*nTpow;
          dis->iparm[j][i] = (int)power;
        }
d1330 1
a1330 2
  const int *doip, *ipowp;
  int    jhat, k, K, lenidx, m, M, MnTpow, n, nKparm, ndparm;
d1334 4
a1337 6
  ndparm = ip[1];
  lenidx = ip[2];
  K      = ip[4];
  M      = ip[5];
  nKparm = ip[6];
  MnTpow = ip[9];
d1348 1
a1348 1
  aux = (double *)(p + ndparm);
d1373 1
a1373 3
  doip  = ip + lenidx;
  ipowp = doip + MnTpow;
  pptr  = p + K*nKparm;
d1378 2
a1379 7
    for (jhat = 0; jhat < Nhat; jhat++, pptr++, doip++, ipowp++) {
      if (*doip) {
        /* The power is integral, multiply in a loop. */       
        for (n = 0; n < *ipowp; n++) {
          term *= rawcrd[jhat];
	}
      } else {
d1385 2
a1386 7
    for (k = 0; k < K; k++, pptr++, doip++, ipowp++) {
      if (*doip) {
        /* The power is integral, multiply in a loop. */       
        for (n = 0; n < *ipowp; n++) {
          term *= aux[k];
	}
      } else {
d1406 1
a1406 1
  int    idp, k, ndparm;
d1423 1
a1423 1
  ndparm = 0;
d1437 1
a1437 1
        if (ndparm < k+1) ndparm = k+1;
d1453 1
a1453 1
  if (ndparm <= 4) {
d1455 1
a1455 1
    ndparm = 4;
d1457 1
a1457 1
  } else if (ndparm <= 7) {
d1459 1
a1459 1
    ndparm = 7;
d1461 1
a1461 1
  } else if (ndparm <= 12) {
d1463 1
a1463 1
    ndparm = 12;
d1465 1
a1465 1
  } else if (ndparm <= 17) {
d1467 1
a1467 1
    ndparm = 17;
d1469 1
a1469 1
  } else if (ndparm <= 24) {
d1471 1
a1471 1
    ndparm = 24;
d1473 1
a1473 1
  } else if (ndparm <= 31) {
d1475 1
a1475 1
    ndparm = 31;
d1477 1
a1477 1
  } else if (ndparm <= 40) {
d1479 1
a1479 1
    ndparm = 40;
d1483 1
a1483 1
      "Invalid number of parameters (%d) for %s", ndparm, id);
a1490 1
  /* Parameters required by disprt(). */
d1492 1
a1492 1
  dis->iparm[j][1] = ndparm;
d1496 1
a1496 1
  if ((dis->dparm[j] = calloc(ndparm, sizeof(double))) == 0x0) {
@


5.1.1.7
log
@Continuing optimization of polyset() and dispoly() yielding a further
speedup of 170%.  The overall speedup from the series of optimizations is
about a factor of x6.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.6 2015/04/13 14:40:20 mcalabre Exp mcalabre $
d1120 3
a1122 3
  int    i, idp, *iparm, ipow, ivar, jhat, k, K, lendp, m, M, naxis, ndparm,
         Nhat, niparm, nKparm, npow, nTparm, nVar, offset;
  double *dparm, *dptr, power;
d1167 2
a1168 2
  nVar   = Nhat + K;
  nTparm = 1 + nVar;
d1171 4
a1174 21
#define I_NIPARM  0	/* Full (allocated) length of iparm[].              */
#define I_NDPARM  1	/* No. of parameters in dparm[], excl. work space.  */
#define I_NIDX    2	/* No. of indexes in iparm[].                       */
#define I_LENDP   3	/* Full (allocated) length of dparm[].              */
#define I_K       4	/* No. of independent variables.                    */
#define I_M       5	/* No. of terms in the polynomial.                  */
#define I_NKPARM  6	/* No. of parameters used to define each auxiliary. */
#define I_NTPARM  7	/* No. of parameters used to define each term.      */
#define I_NVAR    8	/* No. of independent + auxiliary variables.        */
#define I_MNVAR   9	/* No. of powers (exponents) in the polynomial.     */
#define I_DPOLY  10	/* dparm offset for polynomial coefficients.        */
#define I_DAUX   11     /* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  12     /* dparm offset for integral powers of variables.   */
#define I_MAXPOW 13	/* iparm offset for max powers.                     */
#define I_DPOFF  14	/* iparm offset for dparm offsets.                  */
#define I_FLAGS  15	/* iparm offset for flags.                          */
#define I_IPOW   16	/* iparm offset for integral powers.                */
#define NIDX     17

  /* Add extra for integer exponents.  See "Optimization" below. */
  niparm = NIDX + (2 + 2*M)*nVar;
d1179 1
a1179 1
  /* Allocate memory for the indexes and parameter array. */
d1184 14
a1201 24
  /* These help a bit to stop the code from turning into hieroglyphics. */
  iparm = dis->iparm[j];
  dparm = dis->dparm[j];


  /* Record the indexing parameters.  The first two are used by disprt(). */
  iparm[I_NIPARM] = niparm;
  iparm[I_NDPARM] = ndparm;
  iparm[I_NIDX]   = NIDX;
  iparm[I_LENDP]  = lendp;
  iparm[I_K]      = K;
  iparm[I_M]      = M;
  iparm[I_NKPARM] = nKparm;
  iparm[I_NTPARM] = nTparm;
  iparm[I_NVAR]   = nVar;
  iparm[I_MNVAR]  = M*nVar;
  iparm[I_DPOLY]  = K*nKparm;
  iparm[I_DAUX]   = ndparm;
  iparm[I_DVPOW]  = ndparm + K;
  iparm[I_MAXPOW] = iparm[I_NIDX];
  iparm[I_DPOFF]  = iparm[I_MAXPOW] + nVar;
  iparm[I_FLAGS]  = iparm[I_DPOFF]  + nVar;
  iparm[I_IPOW]   = iparm[I_FLAGS]  + M*nVar;

d1203 1
a1203 1
  dptr = dparm + (1 + Nhat);
d1206 1
a1206 1
      dptr[jhat] = 1.0;
d1208 1
a1208 1
    dptr += nKparm;
d1212 1
a1212 1
  dptr = dparm + iparm[I_DPOLY];
d1214 2
a1215 2
    *dptr = 1.0;
    dptr += nTparm;
d1262 1
a1262 1
      dparm[i] = keyp->value.f;
d1280 2
a1281 2
        i = iparm[I_DPOLY] + (m-1)*nTparm;
        dparm[i] = keyp->value.f;
d1292 1
a1292 1
        i = iparm[I_DPOLY] + (m-1)*nTparm + 1 + (jhat-1);
d1294 9
a1302 1
        dparm[i] = power;
d1313 1
a1313 1
        i = iparm[I_DPOLY] + (m-1)*nTparm + 1 + Nhat + (k-1);
d1315 9
a1323 1
        dparm[i] = power;
a1340 65

  /* Optimization: when the power is integral, it is faster to multiply     */
  /* ------------  repeatedly than call pow().  iparm[] is constructed as   */
  /*               follows:                                                 */
  /*     NIDX indexing parameters, as above,                                */
  /*     nVar elements record the largest integral power for each variable, */
  /*     nVar elements record offsets into dparm for each variable,         */
  /*   M*nVar flags to signal whether the power is integral,                */
  /*   M*nVar integral powers.                                              */
  for (ivar = 0; ivar < nVar; ivar++) {
    /* Want at least the first degree power for all variables. */
    i = iparm[I_MAXPOW] + ivar;
    iparm[i] = 1;
  }

  for (ivar = 0; ivar < nVar; ivar++) {
    for (m = 0; m < M; m++) {
      i = iparm[I_DPOLY] + m*nTparm + 1 + ivar;
      power = dparm[i];

      /* Is it integral?  (Positive, negative, or zero.) */
      ipow = (int)power;
      if (power == (double)ipow) {
        /* Signal that the power is integral. */
        i = iparm[I_FLAGS] + m*nVar + ivar;
        if (ipow == 0) {
          iparm[i] = 3;
        } else {
          iparm[i] = 1;
        }

        /* The integral power itself. */
        i = iparm[I_IPOW] + m*nVar + ivar;
        iparm[i] = ipow;
      }

      /* Record the largest integral power for each variable. */
      i = iparm[I_MAXPOW] + ivar;
      if (iparm[i] < abs(ipow)) {
        iparm[i] = abs(ipow);
      }
    }
  }

  /* How many of all powers of each variable will there be? */
  npow = 0;
  for (ivar = 0; ivar < nVar; ivar++) {
    /* Offset into dparm. */
    i = iparm[I_DPOFF] + ivar;
    iparm[i] = lendp + npow;

    i = iparm[I_MAXPOW] + ivar;
    npow += iparm[i];
  }

  /* Expand dparm to store the extra powers. */
  if (npow) {
    lendp += npow;
    iparm[I_LENDP] = lendp;
    if ((dis->dparm[j] = realloc(dparm, lendp*sizeof(double))) == 0x0) {
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }
  }


d1351 2
a1352 2
  const int iparm[],
  const double dparm[],
d1358 11
a1368 4
  const int *iflgp, *imaxp, *imaxpow, *ipowp;
  int    ip, ivar, jhat, k, m;
  const double *cptr, *dpolp, *pptr;
  double *aux, auxp0, *dvarpow, *dpowp, term, var;
d1378 2
a1379 2
  /* Working memory for auxiliaries &c. was allocated at the end of p[]. */
  aux = (double *)(dparm + iparm[I_DAUX]);
d1382 2
a1383 2
  for (k = 0; k < iparm[I_K]; k++) {
    cptr = dparm + k*iparm[I_NKPARM];
a1401 23

  /* Compute all required integral powers of the variables. */
  imaxpow = iparm + iparm[I_MAXPOW];
  dvarpow = (double *)(dparm + iparm[I_DVPOW]);

  imaxp = imaxpow;
  dpowp = dvarpow;
  for (jhat = 0; jhat < Nhat; jhat++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= rawcrd[jhat];
      *dpowp = var;
    }
  }

  for (k = 0; k < iparm[I_K]; k++, imaxp++) {
    var = 1.0;
    for (ip = 0; ip < *imaxp; ip++, dpowp++) {
      var *= aux[k];
      *dpowp = var;
    }
  }

d1404 5
a1408 22
  iflgp = iparm + iparm[I_FLAGS];
  ipowp = iparm + iparm[I_IPOW];
  dpolp = dparm + iparm[I_DPOLY];
  for (m = 0; m < iparm[I_M]; m++) {
    term = *(dpolp++);

    /* Loop over all variables. */
    imaxp = imaxpow;
    dpowp = dvarpow - 1;
    for (ivar = 0; ivar < iparm[I_NVAR]; ivar++) {
      if (*iflgp & 2) {
        /* Nothing (zero power). */

      } else if (*iflgp) {
        /* Integral power. */
        if (*ipowp < 0) {
          /* Negative. */
          term /= dpowp[*ipowp];
        } else {
          /* Positive. */
          term *= dpowp[*ipowp];
        }
d1410 7
d1418 1
a1418 2
        /* Fractional power. */
        term *= pow(dpowp[0], *dpolp);
d1420 1
d1422 10
a1431 6
      iflgp++;
      ipowp++;
      dpolp++;

      dpowp += *imaxp;
      imaxp++;
@


5.1.1.8
log
@Moved the allocation of memory for "returned" disprm struct members from
wcsini() to wcsset().
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.1.1.7 2015/04/15 01:44:40 mcalabre Exp mcalabre $
d108 1
d225 97
d332 17
d415 1
a415 1
    /* Recall that these were allocated in bulk by disset(). */
a638 130
  /* Allocate memory for derived parameters and work arrays. */
  if (dis->i_naxis < naxis) {
    if (dis->i_naxis) {
      /* Recall that axmap, offset, and scale are allocated in bulk. */
      free(dis->axmap[0]);
      free(dis->axmap);
      free(dis->Nhat);
      free(dis->offset[0]);
      free(dis->offset);
      free(dis->scale[0]);
      free(dis->scale);

      for (j = 0; j < dis->i_naxis; j++) {
        /* Memory allocated separately for each axis. */
        if (dis->iparm[j]) free(dis->iparm[j]);
        if (dis->dparm[j]) free(dis->dparm[j]);
      }
      free(dis->iparm);
      free(dis->dparm);

      free(dis->disp2x);
      free(dis->disx2p);

      free(dis->tmpmem);
    }

    if ((dis->axmap = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    /* Allocate axmap[][] in bulk and then carve it up. */
    if ((dis->axmap[0] = calloc(naxis*naxis, sizeof(int))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    for (j = 1; j < naxis; j++) {
      dis->axmap[j]  = dis->axmap[j-1]  + naxis;
    }

    if ((dis->Nhat = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->offset = calloc(naxis, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    /* Allocate offset[][] in bulk and then carve it up. */
    if ((dis->offset[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    for (j = 1; j < naxis; j++) {
      dis->offset[j] = dis->offset[j-1] + naxis;
    }

    if ((dis->scale = calloc(naxis, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    /* Allocate scale[][] in bulk and then carve it up. */
    if ((dis->scale[0] = calloc(naxis*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    for (j = 1; j < naxis; j++) {
      dis->scale[j]  = dis->scale[j-1]  + naxis;
    }

    if ((dis->iparm = calloc(naxis, sizeof(int *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->dparm = calloc(naxis, sizeof(double *))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    /* Carve up the 2D arrays. */
    for (j = 1; j < naxis; j++) {
      dis->axmap[j]  = dis->axmap[j-1]  + naxis;
      dis->offset[j] = dis->offset[j-1] + naxis;
      dis->scale[j]  = dis->scale[j-1]  + naxis;
    }

    if ((dis->disp2x = calloc(naxis, sizeof(int (*)(DISP2X_ARGS)))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->disx2p = calloc(naxis, sizeof(int (*)(DISX2P_ARGS)))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    if ((dis->tmpmem = calloc(5*naxis, sizeof(double))) == 0x0) {
      disfree(dis);
      return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
    }

    dis->i_naxis = naxis;
  }

  /* Start with a clean slate. */
  memset(dis->axmap[0],  0, naxis*naxis*sizeof(int));
  memset(dis->Nhat,      0, naxis*sizeof(int));
  memset(dis->offset[0], 0, naxis*naxis*sizeof(double));

  for (j = 0; j < naxis*naxis; j++) {
    dis->scale[0][j] = 1.0;
  }

  /* polyset() etc. must look after iparm[][] and dparm[][]. */

  dis->i_naxis = naxis;
  dis->ndis    = 0;

  memset(dis->disp2x, 0, naxis*sizeof(int (*)(DISP2X_ARGS)));
  memset(dis->disx2p, 0, naxis*sizeof(int (*)(DISX2P_ARGS)));
  memset(dis->tmpmem, 0, naxis*sizeof(double));


d1182 2
a1183 2
#define I_DAUX   11	/* dparm offset for auxiliary coefficients.         */
#define I_DVPOW  12	/* dparm offset for integral powers of variables.   */
@


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$
d307 3
d558 3
d634 1
a634 1
  int j, naxis, status;
d643 1
d659 2
d663 1
d869 153
@


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


5.0.1.2
log
@New function diswarp() computes various measures of the distortion over
the specified range of coordinates.  disini(), disset(), disprt() handle
disprm::ndis.
@
text
@d25 1
a25 1
  $Id: dis.c,v 5.0.1.1 2015/04/05 12:28:00 mcalabre Exp mcalabre $
a306 3
  dis->ndis = 0;
  dis->padding = 0;

a554 3
  /* Derived values. */
  wcsprintf("       ndis: %d\n", dis->ndis);

d628 1
a628 1
  int j, naxis, ndis, status;
a636 1
  ndis = 0;
a651 2

    ndis++;
a653 1
  dis->ndis = ndis;
a858 153
}

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

int diswarp(
  struct disprm *dis,
  const double pixblc[],
  const double pixtrc[],
  const double pixsamp[],
  int    *nsamp,
  double maxdis[],
  double *maxtot,
  double avgdis[],
  double *avgtot,
  double rmsdis[],
  double *rmstot)

{
  static const char *function = "diswarp";

  int carry, j, naxis, status = 0;
  double dpix, dpx2, dssq, *pix0, *pix1, *pixend, *pixinc, pixspan, *ssqdis,
         ssqtot, *sumdis, sumtot, totdis;
  struct wcserr **err;


  /* Initialize. */
  if (dis == 0x0) return DISERR_NULL_POINTER;
  err = &(dis->err);

  naxis = dis->naxis;

  if (nsamp) *nsamp = 0;
  for (j = 0; j < naxis; j++) {
    if (maxdis) maxdis[j] = 0.0;
    if (avgdis) avgdis[j] = 0.0;
    if (rmsdis) rmsdis[j] = 0.0;
  }
  if (maxtot) *maxtot = 0.0;
  if (avgtot) *avgtot = 0.0;
  if (rmstot) *rmstot = 0.0;

  /* Quick return if no distortions. */
  if (dis->ndis == 0) return 0;

  /* Carve up working memory, noting that disp2x() gets to it first. */
  pixinc = dis->tmpmem + naxis;
  pixend = pixinc + naxis;
  sumdis = pixend + naxis;
  ssqdis = sumdis + naxis;

  /* Work out increments on each axis. */
  for (j = 0; j < naxis; j++) {
    pixspan = pixtrc[j] - (pixblc ? pixblc[j] : 1.0);

    if (pixsamp == 0x0) {
      pixinc[j] = 1.0;
    } else if (pixsamp[j] == 0.0) {
      pixinc[j] = 1.0;
    } else if (pixsamp[j] > 0.0) {
      pixinc[j] = pixsamp[j];
    } else if (pixsamp[j] > -1.5) {
      pixinc[j] = 2.0*pixspan;
    } else {
      pixinc[j] = pixspan / ((int)(-pixsamp[j] - 0.5));
    }
  }

  /* Get some more memory for coordinate vectors. */
  if ((pix0 = calloc(2*naxis, sizeof(double))) == 0x0) {
    return wcserr_set(DIS_ERRMSG(DISERR_MEMORY));
  }

  pix1 = pix0 + naxis;


  /* Set up the array of pixel coordinates. */
  for (j = 0; j < naxis; j++) {
    pix0[j] = pixblc ? pixblc[j] : 1.0;
    pixend[j] = pixtrc[j] + 0.5*pixinc[j];
  }

  /* Initialize accumulators. */
  for (j = 0; j < naxis; j++) {
    sumdis[j] = 0.0;
    ssqdis[j] = 0.0;
  }
  sumtot = 0.0;
  ssqtot = 0.0;


  /* Loop over N dimensions. */
  carry = 0;
  while (carry == 0) {
    if ((status = disp2x(dis, pix0, pix1))) {
      wcserr_set(DIS_ERRMSG(status));
      goto cleanup;
    }

    /* Accumulate statistics. */
    (*nsamp)++;

    dssq = 0.0;
    for (j = 0; j < naxis; j++) {
      dpix = pix1[j] - pix0[j];
      dpx2 = dpix*dpix;

      sumdis[j] += dpix;
      ssqdis[j] += dpx2;

      if (maxdis && (dpix = fabs(dpix)) > maxdis[j]) maxdis[j] = dpix;

      dssq += dpx2;
    }

    sumtot += totdis;
    ssqtot += totdis*totdis;

    totdis = sqrt(dssq);
    if (maxtot && *maxtot < totdis) *maxtot = totdis;

    /* Next pixel. */
    for (j = 0; j < naxis; j++) {
      pix0[j] += pixinc[j];
      if (pix0[j] < pixend[j]) {
        carry = 0;
        break;
      }

      pix0[j] = pixblc ? pixblc[j] : 1.0;
      carry = 1;
    }
  }


  /* Compute the means and RMSs. */
  for (j = 0; j < naxis; j++) {
    ssqdis[j] /= *nsamp;
    sumdis[j] /= *nsamp;
    if (avgdis) avgdis[j] = sumdis[j];
    if (rmsdis) rmsdis[j] = sqrt(ssqdis[j] - sumdis[j]*sumdis[j]);
  }

  ssqtot /= *nsamp;
  sumtot /= *nsamp;
  if (avgtot) *avgtot = sumtot;
  if (rmstot) *rmstot = sqrt(ssqtot - sumtot*sumtot);


cleanup:
  free(pix0);

  return status;
@


0.0
log
@Empty revision.
@
text
@d1 1153
@
