1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284
|
// Copyright 2021 - Unistra/CNRS
// The MOC API project is distributed under the terms
// of the GNU General Public License version 3.
//
//This file is part of MOC API java project.
//
// MOC API java project is free software: you can redistribute it and/or modify
// it under the terms of the GNU General Public License as published by
// the Free Software Foundation, version 3 of the License.
//
// MOC API java project is distributed in the hope that it will be useful,
// but WITHOUT ANY WARRANTY; without even the implied warranty of
// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
// GNU General Public License for more details.
//
// The GNU General Public License is available in COPYING file
// along with MOC API java project.
//
package cds.moc;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.Iterator;
/**
* The SMoc class implements the methods specific to spatial MOCs.
* It is based on the HEALpix tesselation of the sphere.
* See: IVOA MOC 2.0 standard => https://www.ivoa.net/documents/MOC/
* @author Pierre Fernique [CDS]
* @version 1.0 - April 2021 - creation
*
*/
public class SMoc extends Moc1D {
static final public int MAXORD_S = 29; // Max order (<=> deepest HEALPix level)
static final public int FACT_S = 4; // Factor between two consecutive order
static final public char DIM_S = 's'; // Char signature for SMoc
static final public long NBVAL_S = pow2( MAXORD_S ) * pow2( MAXORD_S ) * 12L; // nb of cells at the deepest order
static final public String SYS_S = "C"; // Celestial coordinate system
private int minOrder; // Min order, 0 by default
/** Return the deepest possible order (ex: 29 for SMoc, 61 for TMoc) */
public final int maxOrder() { return MAXORD_S; }
/** Return the number of bit shifting between two consecutive orders (ex: 2 for SMoc, 1 for TMoc) */
public final int shiftOrder() { return FACT_S/2; }
/** Return the Moc signature character (ex: 's' for SMoc, 't' for TMOC) */
public final char cDim() { return DIM_S; }
/** Return the number of values at the deepest order (ex: 2x2^29x2^29 for SMoc, 2^61 for TMoc) */
public final long maxVal() { return NBVAL_S; }
/** Return the default reference system */
public final String sys() { return SYS_S; }
public SMoc() { super(); }
public SMoc( int mocOrder ) { super( mocOrder ); }
public SMoc( String s ) throws Exception { super(s); }
public SMoc( SMoc moc ) throws Exception { super( moc ); }
public SMoc( InputStream in ) throws Exception { super(in); }
/** Reinitialisation of the MOC - data only (not the properties) */
public void clear() {
super.clear();
minOrder=0;
}
/** Clone Moc (deep copy) */
public SMoc clone() throws CloneNotSupportedException {
SMoc moc = dup();
clone1( moc );
return moc;
}
/** Deep copy. The source is this, the target is the Moc in parameter */
protected void clone1( Moc moc ) throws CloneNotSupportedException {
if( !(moc instanceof SMoc) ) throw new CloneNotSupportedException("Uncompatible type of MOC for clone. Must be SMoc");
super.clone1( moc );
((SMoc)moc).minOrder = minOrder;
}
/** Create and instance of same class, same sys, but no data nor mocorder */
public SMoc dup() {
SMoc moc = new SMoc();
moc.sys=sys;
return moc;
}
/** Return the number of bytes used for coding each FITS value (4 for integer, 8 for long) */
public int sizeOfCoding() { return getDeepestOrder()<14 ? 4 : 8; }
/** Return the number of values to write in FITS serialization */
public int getNbCoding() { return getNbCells(); }
/** Add directly a SMoc */
public void add(Moc moc) throws Exception {
if( !(moc instanceof SMoc) ) throw new Exception("Uncompatible Moc for adding");
super.add(moc);
}
/************************************ SMoc specifical methods => HEALPix *****************************************/
/** Add a Moc pixel (at max order) corresponding to the alpha,delta position
* @param alpha, delta position
* @return true if the cell (or its father) has been effectively inserted
*/
public void add(HealpixImpl healpix,double alpha, double delta) throws Exception {
int order = getMocOrder();
if( order==-1 ) throw new Exception("Undefined Moc order");
long npix = healpix.ang2pix(order, alpha, delta);
add(order,npix,npix);
}
/** Check if the spherical coord is inside the MOC. The coordinate system must be compatible
* with the MOC coordinate system.
* @param alpha in degrees
* @param delta in degrees
* @return true if the coordinates is in one MOC pixel
* @throws Exception
*/
public boolean contains(HealpixImpl healpix,double alpha, double delta) throws Exception {
int order = getDeepestOrder();
if( order==-1 ) return false;
long npix = healpix.ang2pix(order, alpha, delta);
return isIncluding(order,npix);
}
/**
* Provide Moc pixels totally or partially inside a circle
* @param alpha circle center (in degrees)
* @param delta circle center (in degrees)
* @param radius circle radius (in degrees)
* @return an HealpixMox containing the list of pixels
* @throws Exception
*/
public SMoc queryDisc(HealpixImpl healpix,double alpha, double delta,double radius) throws Exception {
int order = getDeepestOrder();
if( order==-1 ) return null;
SMoc mocA = dup();
long [] list = healpix.queryDisc(order, alpha, delta, radius);
for( long npix : list ) mocA.add(order,npix,npix);
return intersection(mocA);
}
/** Set alternative Coosys. All celestial SMoc must be expressed in ICRS (see IVOA MOC 2.0)
* but alternative is possible for other sphere coverage notably the planets
* @param coosys alternative coosys keyword (not standardized in IVOA document)
*/
public void setSpaceSys( String coosys ) { setSys(coosys); }
/** Get the Coosys. See setSpaceSys() */
public String getSpaceSys() { return getSys(); }
/** Set min Moc min Order. The hierarchical view will be start at this order. 0 by default */
public void setMinOrder( int minOrder ) throws Exception {
if( minOrder==this.minOrder ) return;
if( minOrder<0 || minOrder>maxOrder() ) throw new Exception("MinOrder error ("+minOrder+" not in [0.."+maxOrder()+"])");
if( mocOrder!=-1 && minOrder>mocOrder ) throw new Exception("MinOrder cannot be bigger that Moc order");
this.minOrder = minOrder;
resetCache();
}
/** get min Moc min Order. The hierarchical view will be start at this order. 0 by default */
public int getMinOrder() { return minOrder; }
/** Provide the angular resolution (in degrees) of the SMoc (sqrt of the smallest pixel area) */
public double getAngularRes() {
return Math.sqrt( Healpix.getPixelArea( getMocOrder() ) );
}
/** True if the npix at the deepest order is in the MOC */
public boolean contains(long npix) { return range.contains(npix); }
/***************************************************** Operations ******************************************/
public boolean isIncluding(Moc moc) throws Exception {
if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc isIncluding test");
if( !((SMoc)moc).isCompatible( this ) ) throw new Exception("Uncompatible sys");
flush();
return range.contains( ((SMoc)moc).range );
}
public boolean isIntersecting(Moc moc) throws Exception {
if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc isIncluding test");
flush();
return range.overlaps( ((SMoc)moc).range );
}
/** Return the Union with another Moc */
public SMoc union(Moc moc) throws Exception {
if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc union");
return (SMoc) super.union(moc);
}
/** Return the Intersection with another Moc */
public SMoc intersection(Moc moc) throws Exception {
if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc subtraction");
return (SMoc) super.intersection(moc);
}
/** Return the subtraction with another Moc */
public SMoc subtraction(Moc moc) throws Exception {
if( moc instanceof STMoc ) moc = ((STMoc)moc).getSpaceMoc();
else if( !(moc instanceof SMoc ) ) throw new Exception("Uncompatible Moc type for SMoc subtraction");
return (SMoc) super.subtraction(moc);
}
/** Return the complement */
public SMoc complement() throws Exception { return (SMoc) super.complement(); }
/*************************************************************** I/O *****************************************************/
/** Internal method: read FITS data according to the type of MOC.
* @param in The input stream
* @param naxis1 size of FITS row (in bytes) (generally ==nbyte, but may be 1024 for buffering)
* @param naxis2 number of values
* @param nbyte size of each value (in bytes)
* @param header HDU1 header
* @throws Exception
*/
protected void readSpecificData(InputStream in, int naxis1, int naxis2, int nbyte, HeaderFits header) throws Exception {
// Moc order detection
int mocOrder=-1;
String val = header.getStringFromHeader("MOCORD_S");
if( val==null ) val = header.getStringFromHeader("MOCORDER"); // Compatibility with MOC 1.0 and 1.1
try { mocOrder = Integer.parseInt(val); }
// catch( Exception e ) { throw new Exception("Missing MOC order in FITS header (MOCORD_S)"); }
catch( Exception e ) { }
setMocOrder( mocOrder );
String type = header.getStringFromHeader("ORDERING");
String sys = header.getStringFromHeader("COORDSYS");
if( sys!=null && !sys.equals("C") ) setSpaceSys(sys);
// We anticipate the SMOC coded in RANGE (not possible in IVOA M0C 2.0) => Range coding
if( type!=null && type.equals("RANGE") ) readSpecificDataRange(in, naxis1, naxis2, nbyte);
// Regular SMOC coding => NUNIQ
else readSpecificDataUniq(in, naxis1, naxis2, nbyte);
}
/** Write specifical SMOC properties */
protected int writeSpecificFitsProp( OutputStream out ) throws Exception {
int n=0;
out.write( getFitsLine("TTYPE1","UNIQ","UNIQ pixel number") ); n+=80;
out.write( getFitsLine("ORDERING","NUNIQ","NUNIQ coding method") ); n+=80;
out.write( getFitsLine("COORDSYS",getSpaceSys(),"Space reference frame") ); n+=80;
out.write( getFitsLine("MOCDIM","SPACE","Physical dimension") ); n+=80;
out.write( getFitsLine("MOCORD_S",""+getMocOrder(),"MOC resolution (best order)") ); n+=80;
out.write( getFitsLine("MOCORDER",""+getMocOrder(),"=MOCORD_S (backward compatibility)") ); n+=80;
return n;
}
/** Write SMOC data -> hierarchy mode */
protected int writeSpecificData(OutputStream out) throws Exception {
int size = 0;
byte [] buf = new byte[ sizeOfCoding() ];
Iterator<MocCell> it = cellIterator( true );
while( it.hasNext() ) {
MocCell cell = it.next();
for( long val=cell.start; val<cell.end; val++ ) {
long nuniq = hpix2uniq(cell.order, val );
size+=writeVal(out,nuniq,buf);
}
}
return size;
}
}
|