/**
     *
     * @param lowerWhich
     * @param lowerValue
     * @param upperWhich
     * @param upperValue
     * @param asinhQValue
     * @param gammaValue
     * @param algorithm
     * @param zscaleContrast
     * @param zscaleSamples
     * @param zscaleSamplesPerLine
     * @param rgbPreserveHue
     * @param asinhStretch used for hue preserving rgb, when NaN use zscale to estimate stretch value
     * @param scalingK used for hue preserving rgb
     * @param bias
     * @param contrast
     * @return {RangeValues}
     */


/**
     *
     * @param boundsType one of 'percent', 'absolute', 'sigma'
     * @param lowerValue lower value of stretch, based on stretchType
     * @param upperValue upper value of stretch, based on stretchType
     * @param algorithm one of 'linear', 'log', 'loglog', 'equal', 'squared', 'sqrt', 'asinh', powerlaw_gamma'
     * @return {*}
     */


/**
     *
     * @param boundsType one of 'percent', 'absolute', 'sigma'
     * @param lowerValue lower value of stretch, based on stretchType
     * @param upperValue upper value of stretch, based on stretchType
     * @param algorithm one of 'log', 'loglog', 'equal', 'squared', 'sqrt', 'asinh', powerlaw_gamma'
     * @return {*}
     */


/**
     * @param sIn serialized string representation of RangeValues
     * @return {RangeValues}
     */


/**
 *
 * @param s
 * return {{lon:number,lat:number,cSys:CoordinateSys}|false}
 */


/**
 * @param {PlotView[]|PlotView|VisRoot|CysConverter|WebPlot} ref this can be the visRoot or the plotViewAry, or a plotView Object.
 * @param {Boolean} includeNoncelestial if True include non-celestial coordinate systems into consideration
 * @return {boolean} true if there is a projection for recognized celestial system by default or,
 *  if unrecognizedCelestial is true, for any coordinate system with recognized projection algorithm.
 */


/**
 *
 * @param {WebPlot|PlotView} plotOrPv plot or plotView object.  if a PlotView then it test the primePlot of the plotView
 * @return {boolean} true if three color false if not or plot is null
 */


/**
 *
 * @param {VisRoot} visRoot
 * @param plotId
 */


/**
 * Perform an operation on all the PlotViews in a group except the source, get the plotViewAry and group from the store.
 * The operations are only performed if the group is locked.
 * @param {VisRoot} visRoot - root of the visualization object in store
 * @param {PlotView} sourcePv
 * @param {Function} operationFunc
 * @param {boolean} ignoreThreeColor
 * @param {boolean} anyPlotType
 * @return {Array} new plotView array after the operation
 */


/**
 * Perform an operation on all the PlotViews in a group except the source a return a new version of the plotViewAry
 * The operations are only performed if the group is locked.
 * Typically used inside of reducer
 * @param {VisRoot} vr
 * @param sourcePv
 * @param plotViewAry
 * @param {boolean} matchAnyType matching across plot types ie, would return a hips or an image
 * @param {Function} operationFunc the function to operate on the other plot views
 * @param {PlotView} operationFunc.param pv the PlotView to operate on
 * @return {Array.<PlotView>} new plotView array after the operation
 */


/**
 * perform an operation on a plotView or its related group depending on the lock state.
 * Typically, used inside of reducer.
 * @param {boolean} toAll
 * @param {Array.<PlotView>} plotViewAry plotViewAry
 * @param {string} plotId the that is primary.
 * @param {boolean} matchAnyType matching across plot types ie, would return a hips or an image
 * @param {Function} operationFunc the function to operate on the other plot views
 * @param {PlotView} operationFunc.param pv the PlotView to operate on
 * @return {Array.<PlotView>|undefined} new plotViewAry if plotId has no PlotView
 */


/**
 *
 * @param {PlotView} pv plot view
 * @return {boolean}
 */


/**
 * Find the point in the plot that is at the center of the display.
 * The point returned is in ImagePt coordinates.
 * We return it in and ImagePt not screen because if the plot is zoomed the image point will still
 * be what we want in the center. A alternate scrollX and scrollY may be passed otherwise the current
 * scrollX and scrollY is used.
 *
 * @param {PlotView} plotView
 * @param {number} [scrollX] optional scrollX, if not defined use plotView.scrollX
 * @param {number} [scrollY] optional scrollY, if not defined use plotView.scrollY
 * @return {ImagePt|undefined} the center point
 */


/**
 * Given a HDU index and optionally a cube index, return the image idx
 * @param {PlotView|undefined} pv
 * @param {number} hduIdx
 * @param {number|'follow'} cubeIdx
 * @return {number|undefined} the hdu number or undefined if bad parameters
 */


/**
 * Give a image index return the hduIndx and optionally the cubeIdx
 * @param {PlotView} pv
 * @param {number} imageIdx
 * return {{hduIdx:number, cubeIdx:number, isCube:boolean}}
 */


/**
 * Check if two PlotViews are equals by comparing only certain keys
 * @param {PlotView} pv1
 * @param {PlotView} pv2
 * @param {Array.<String>} pvKeys
 * @param {Array.<String>} plotKeys
 */


/**
 * Return true if the plot in both PlotViews are rotated the same
 * @param {PlotView} pv1
 * @param {PlotView} pv2
 * @return {boolean}
 */


/**
 * return true if the plotview can be converted between HiPS and FITS
 * @param {PlotView} pv
 * @return {boolean}
 */


/**
 * make rectangle drawobj with the center and rotate angle specified
 * @param pt1
 * @param width
 * @param height
 * @param unitType
 * @param angle
 * @param angleUnit
 * @param isOnWorld if the rectangle have the width and height move along the east and north direction over the world domain
 * @param centerInView
 * @returns {Object}
 */


/**
 * calculate the rectangle slanted angle on the screen
 * the angle is in clockwise direction, consistent with canvas drawing
 *
 * return the upperLeft corner, dimension and slanted angle of the rectangle in screen or image coordinate
 * and the center of the rectangle
 *
 * @param wpt
 * @param {CysConverter} plot
 * @param isCenter
 * @param width
 * @param height
 * @param unit
 * @param isOnWorld
 * @returns {{width: *, height: *, unit: *, angle: *}} angle in radian on image coordinate, height, width in image pixel
 */


/**
 * compute if any of the 4 corners of rect is in viewport
 * @param cornerAry world coordinate
 * @param {CysConverter} plot
 * @returns {boolean}
 */


/**
 * @param drawObj
 * @param ctx
 * @param {CysConverter} plot
 * @param inPt
 * @param drawParams
 * @return {boolean} text is drawn or not
 */


/**
 * draw the object which contains drawObj array
 * @param drawObj
 * @param ctx
 * @param {CysConverter} plot
 * @param drawParams
 * @param onlyAddToPath
 */


/**
 * draw polygon - draw outline of the polygon or fill the polygon
 * @param drawObj
 * @param ctx
 * @param {CysConverter} plot
 * @param drawParams
 * @param onlyAddToPath
 */


/**
 * locate text for circle, return the location in screen coordinate
 * @param {CysConverter} plot
 * @param textLoc
 * @param fontSize
 * @param centerPt
 * @param screenRadius
 * @return {null}
 */


/**
 * locate text position for line in screen coordinate
 * @param {CysConverter} plot
 * @param textLoc
 * @param fontSize
 * @param inPt0
 * @param inPt1
 * @param tIndex text line number for multipe text lines on LINE_TOP_STACK location style
 * @param drawObj line obj
 * @return {ScreenPt}
 */


/**
 * compute text location for rectangle in screen coordinate
 * @param {CysConverter} plot
 * @param textLoc
 * @param fontSize
 * @param centerPt
 * @param width
 * @param height
 * @param angle
 * @param lineWidth
 * @returns {ScreenPt} screen point
 */


/**
 * compute text location for ellipse in screen coordinate
 * @param {CysConverter} plot
 * @param textLoc
 * @param fontSize
 * @param centerPt
 * @param radius1  radius on horizotal axis
 * @param radius2  radius on vertical axis
 * @param angle    in radian
 * @param lineWidth
 * @returns {ScreenPt} screen location
 */


/**
 * compute text location for annulus-like and polygon shape
 * @param cc
 * @param textLoc
 * @param fontSize
 * @param width     in screen coordinate
 * @param height
 * @param centerPt
 * @param lineWidth
 * @returns {ScreenPt}
 */


/**
 * apt could be image or screen coordinate
 * @param {CysConverter} plot
 * @param pts
 * @param apt
 * @returns {*}
 */


/**
 * rotate the obj around a center pt
 * @param drawObj
 * @param {CysConverter} plot
 * @param angle in screen coordinate direction, radian
 * @param worldPt
 * @returns {*}
 */


/**
 * rotate an array of points around a center on image coordinate
 * @param {CysConverter} plot
 * @param pts
 * @param angle in screen coordinate direction, radian
 * @param wc
 * @returns {*}
 */


/**
 * check if at least one corner of the covered area (in image coordinate) is within viewport
 * @param objArea
 * @param {CysConverter} plot
 * @returns {boolean}
 */


// calculate the font height in screen coordinate based on given font size


/**
 * calculate the length in screen coordinate
 * @param r
 * @param {CysConverter} plot
 * @param unitType
 * @returns {*}
 */


/**
 * calculate the length in world coordinate
 * @param r
 * @param {CysConverter} plot
 * @param unitType
 * @returns {*}
 */


/**
 * calcuate the horizontal and vertical coverage after rotating a rectagle with width and height
 * @param width
 * @param height
 * @param angle
 * @returns {number}
 */


/**
 * generate region description
 * @param drawObj
 * @param plot   primePlot
 * @param drawParams
 * @return {Array}
 */


/**
 * generate region description for text
 * @param inPt
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {*}
 */


/**
 * add text related property to the region description.
 *
 * note: for current version, a seperate text region is created if either non default textloc or textoffset exists.
 *
 * @param drawObj
 * @param drawParams
 * @returns {*}
 */


/**
 * create text region seperate from the region of any shape in case there exists non default textloc or textoffset or
 * a seperate request.
 * @param drawObj
 * @param drawParams
 * @param regionType
 * @param cc
 * @returns {*}
 */


/**
 * handle text associted with the region
 * if the textloc or textoffset is not set as default, then create seperate text region line,
 * or attach the text to the original regiopn shape
 * @param retList
 * @param crtRegionDes
 * @param drawObj
 * @param drawParams
 * @param regionType
 * @param cc
 */


/**
 * generate region description for line and the associated text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 *
 * @param plot
 * @param pts
 * @return {number}
 */


/**
 * create RegionValue (defined in Region.js) based on value and unit in terms of UnitType
 * @param r
 * @param unitType
 */


/**
 * create RegionValue based on angle and angleUnit, the return is in unit of degree
 * @param cc
 * @param angle
 * @param angleUnit
 * @returns {*}
 */


/**
 * generate region description for circle and the associated text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 * generate region description for box and the associated text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 * generate region description for ellipse and the associated text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 * generate region annulus and associated text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 * generate region description for boxannulus and the associated text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 * generate region description for polygon and the associted text
 * @param pts
 * @param cc
 * @param drawObj
 * @param drawParams
 * @returns {Array}
 */


/**
 *
 * @param {string} drawLayerId
 * @param {string} drawLayerTypeId
 * @param {string|{}} title can be a string title or an object {plotId:title}
 * @param {object} options a set of options that define this drawing layer All boolean options default to false
 *                 unless specified and string options to the empty string
 * @param {boolean} [options.canHighlight] if the layer can highlight
 * @param {boolean} [options.canSelect]    supports a selected array of objects, must be able to produce a selected data array,
 *                               only used with isPointData
 * @param {boolean} [options.canShowSelect]  supports a selected array of objects, must be able to produce a selected data array,
 *                               used to show the selected data
 * @param {boolean} [options.canFilter]    drawing layer can be used with the filter controls,
 *                               only used with canSelect and isPointData
 * @param {boolean} [options.canUseMouse]  drawing layer has mouse interaction, must set up actionTypeAry
 * @param {boolean} [options.hasPerPlotData] drawing layer produces different data for each plot
 * @param {boolean} [options.isPointData] drawing layer only uses point data, @see PointDataObj.js
 * @param {boolean|string} [options.canUserChangeColor] drawing layer color can be changed by the user,
 *                                   can be DISABLE,DYNAMIC, or STATIC, default: STATIC
 * @param {boolean} [options.canUserDelete] drawing layer can be deleted by the user, default: true
 * @param {string} [options.helpLine] a one line string describing the operation, for the end user to see
 * @param {boolean} [options.canAttachNewPlot] can be attached to new plot created after the drawing layer is created
 *
 * @param {object} drawingDef  the defaults that the drawer will use if not overridden by the object @see DrawingDef
 * @param {Array} actionTypeAry extra [actions] that are allow though to the drawing layer reducer
 * @param {object} mouseEventMap object literal with event to function mapping, see documentation below in object
 * @param {object} exclusiveDef
 * @param {function} getCursor
 * @return {DrawLayer}
 */


/**
 * drawObj for point, optional: textLoc
 * @param {Point|WorldPt} pt
 * @param {number} [size]
 * @param {Enum} [symbol]
 * @param {string} [text]
 * @param {Object} [renderOptions]
 * @return {object}
 */


/**
 * translate the point symbol
 * @param {WebPlot} plot
 * @param drawObj
 * @param apt
 * @returns {{pt: *}}
 */


/**
 * rotate the point symbol (rotate the point defined for the point, not the entire symbol)
 * if the entire symbol needs to be rotated, set the angle to renderOptions.rotAngle externally
 * @param {WebPlot} plot
 * @param drawObj
 * @param {number} angle in screen coodinate direction, radian
 * @param {WorldPt} worldPt
 * @returns {{pt: *}}
 */


/**
 * calculate the text location based on text location, offset, font size, point size and point symbol.
 * @param {CanvasRenderingContext2D} ctx
 * @param drawObj
 * @param plot
 * @param textLoc
 * @param text
 * @returns {*}
 */


/**
 * @summary render highlight on top of region
 * @param drawObj
 * @param color
 * @param style
 * @param lineW
 * @returns {*}
 */


/**
 * @summary make drawobj to highlight PointDataObj
 * @param {Object} drawObj
 * @param {Object} cc
 * @param {Object} def
 * @returns {Object} inside or not and the distance to the point center
 */


/**
 * check if a specified point is within PointDataobj
 * @param drawObj
 * @param cc
 * @param pt
 * @returns {{inside: *, dist: *}}
 */


/**
 * This function is just a convenience to create a draw factory definition object literal. You don't have
 * to use it.  You can create the object directly.
 * Every drawing layer needs a drawing
 * factory definition to manage it. All drawing layer modules must export an factoryDef object. The factoryDef should
 * the following properties.
 *
 * drawLayerTypeId - string, required- type id of the drawLayer
 * create -function, function, required-  that will create a new draw layer of this type
 *
 * @param drawLayerTypeId
 * @param {DrawLayerDefinition~creator} create
 * @param {DrawLayerDefinition~getDrawData} [getDrawDataFunc]
 * @param {DrawLayerDefinition~getLayerChanges} [getLayerChanges] get the changes to incorporate into the drawing layer object
 * @param {object} onDetachAction
 * @param {object} [getUIComponent] react component react pure function component, optional- react component
 * @param {object} onVisibilityChange
 * @return {DrawLayerDefinition}
 */


/**
     *
     * @param drawLayerTypeId
     * @param initPayload
     * @return {*}
     */


/**
 *
 * @param canvas
 * @param drawingDef
 * @param {CsysConverter} csysConv
 * @param data
 * @param {number} maxChunk
 * @param {Function} deferredDrawingCompletedCB - called when drawing has completed
 * @param copyToCanvas
 * @return {Object}
 */


/**
 * An optimization of drawing.  Check is the Object is a PointDataObj (most common and simple) and then checks
 * it is draw on a WebPlot, and if it is in the drawing area.
 * Otherwise it will always return true
 * @param {CysConverter} csysConv the WebPlot to draw on
 * @param {DrawObj} obj the DrawingObj to check
 * @return {boolean} true is it should be drawn
 */


/**
     * get command string on the dropdown list given mission string
     * @param mission
     * @returns {string} null for no content
     */


/**
 * Draw one or more closed polygons.
 *
 * This class can only be used with a WebPlot, You must use WorldPt
 *
 * @author tatianag, Trey
 * @version $Id: FootprintObj.java,v 1.14 2012/11/30 23:17:01 roby Exp $
 *
 * @param {Array.<WorldPt[]>} footprintAry an array of arrays of WorldPt, each array represents 1 footprint
 * @param {Enum} style
 * @return {object}
 */


/**
 *
 * @param {number} x1 the coordinates of the beginning of the specified line segment
 * @param {number} y1 the coordinates of the beginning of the specified line segment
 * @param {number} x2 the coordinates of the end of the specified line segment
 * @param {number} y2 the coordinates of the end of the specified line segment
 * @param {number} px the coordinates of the specified point being measured against the specified line segment
 * @param {number} py the coordinates of the specified point being measured against the specified line segment
 * @return {number} a double value that is the square of the distance from the
 *         specified point to the specified line segment.
 */


/**
 * Object to hold defaults for drawing a group of objects.
 *
 * @param color
 * @param presetDefaults
 * @return {DrawingDef}
 */


//for one footprint drawobj, one of connectedObjs in ImageLineBaseObj


// draw one footprint drawobj


// footprint data to connect object


/**
 * convert all connectObjs for the set of footprint unit into a array of drawObjs for display
 * @param imageLineObj
 * @param displayMode
 * @param color
 * @param showText
 * @param symbol
 * @param hideId
 * @returns {connectedObjs|*}
 */


/**
 * create rectangle drawObjs based on the one or zero segments in the ImageLineBasedObj
 * @param imageLineObj
 * @param bCovered   one segment or zero segment
 * @param color      optional
 * @param style      optional
 * @param hideId
 */


/**
 * create polygon drawObjs based on the footprint data unit
 * @param imageLineObj
 * @param showText  if showing text
 * @param color     outline color
 * @param fillColor fill color
 * @param style     fill or outline
 * @param hideId    if hiding the display
 * @param bRemoveExist  optional reset the polygon objects
 */


/**
 * create point drawObjs based on the footprint peaks
 * @param imageLineObj
 * @param color
 * @param symbol
 * @param hideId
 * @returns {*}
 */


/**
     * an object containing array of '1' segments at each row, row is the key and array of '1' segments is the value.
     * @returns {{zeroSegments: ({}|*)}}
     */


/**
     * an object containing array of '0' segments at each row, row is the key and array of '0' segments is the value.
     * @returns {{zeroSegments: ({}|*)}}
     */


/**
     * make rect drawobj on covered or uncovered area, based on '1' or '0' segments
     * @param makeImgPt
     * @param bCovered
     * @returns {*}
     */


// one footprint may contain more than one polygon


/**
 * check if the shape coverage area is inside the plot area
 * @param cc
 * @param drawObj    drawObj & coverArea could be exclusive
 * @param coverArea
 * @param def
 * @returns {*} the upperLeft corner and the covered width and height
 */


/**
 * check if any given point is inside the region on the screen with the consideration of line width
 * @param drawObj
 * @param pt
 * @param cc
 * @param def
 * @returns {*}
 */


/**
 * check if the screen point is inside a polygon (either convex or non-convex)
 * @param sPt
 * @param corners
 * @param cc
 * @param lineWidth
 * @returns {boolean}
 */


/**
 * rotate rotate point [x, y] around [0, 0]
 * @param sPt
 * @param angle
 */


/**
 * check if a screen point is in touch with a line (within in very close distance)
 * @param drawObj
 * @param sPt
 * @param cc
 * @returns {*} inside or not and the vertical or horizontal distance to the line
 */


/**
 * check if a screen point is within a circle,
 * @param drawObj
 * @param sPt
 * @param cc
 * @param def
 * @returns {*} inside or not  and the distance to the center
 */


/**
 * check if a screen point is within a rectangle (or a rectangle with rotate angle)
 * @param drawObj
 * @param sPt
 * @param cc
 * @param def
 * @returns {*} inside or not and the the distance to the center
 */


/**
 * check if a screen point is within a (rotated) ellipse
 * @param drawObj
 * @param sPt
 * @param cc
 * @param def
 * @returns {*} inside or not and the distance to the center
 */


/**
 * check if a screen point is within the polygon
 * @param drawObj
 * @param sPt
 * @param cc
 * @returns {*} inside or not and the distance to the center of the polygon
 */


/**
 * rendering option for highlight box
 * @param dObj
 * @param color
 */


/**
 * generate rectangle drawObj to wrap around the highlighted object
 * @param drawObj
 * @param cc
 * @param def
 * @returns {*}
 */


/**
 *
 * @param ctx
 * @param {String} text
 * @param {number} x
 * @param {number} y
 * @param {String} color
 * @param {Object} renderOptions
 * @param {Object} locationOptions
 * @param {String} locationOptions.textBaseline
 * @param {String} locationOptions.textAlign
 * @param {number} locationOptions.rotationAngle angle in degrees
 * @param {Object} fontOptions
 * @param {String} [fontOptions.fontFamily]
 * @param {String} [fontOptions.size]
 * @param {String} [fontOptions.fontWeight]
 * @param {String} [fontOptions.fontStyle]
 */


/**
 * start fill path
 * @param {object} ctx
 * @param {object} [renderOptions]
 * @param {string} color
 * @param {string} strokeColor
 */


/**
 * @desc draw rotate symbol in the western location
 * @param ctx
 * @param x (x, y) point to the end of the bar of rotate symbol
 * @param y
 * @param color
 * @param size
 * @param lineWidth
 * @param renderOptions
 * @param onlyAddToPath
 */


/**
 * add a solid arrow to the second end of the line
 * @param ctx
 * @param fromPt in device coordinate
 * @param toPt   in device coordinate
 * @param color
 */


/**
 * Draw one or more polygons defined in Multi-Order Coverage Map, MOC.
 * properties in DrawObj:
 *   drawObjAry: set of polygon drawObj
 *   regions:    set of polygon regions
 *   cellNums:   cell number list
 *
 * @param {Array} cellNums MOC cell number list
 * @param {Object} drawingDef
 * @param mocCsys
 * @return {object}
 */


// first step filter out invisible tiles by looking at low  order parent tile


// select visible tile from the MOC at order 0 (visible map not include visible tiles at order 0)


// find visible tile for the MOC by checking the visible map


// create one drawObj for one tile


// create all drawObjs


/**
 *
 * @param {{x:name,y:name,type:string}} pt1 first corner
 * @param {{x:name,y:name,type:string}} pt2  second corner
 * @param {Enum} [style]
 * @return {object}
 */


/**
 * Create a DrawObj for footprint or marker that contains the following:
 *  obj.text= null;
 *  obj.fontName
 *  obj.fontSize
 *  obj.fontWeight
 *  obj.fontStyle
 *  obj.width
 *  obj.height
 *  obj.color
 *  obj.style=Style.STANDARD;
 *  obj.sType = MarkerType.Marker or MarkerType.Footprint
 *  obj.unitType
 *  obj.includeRotate = true|false  if (isRotatable === true), show outlinebox + rotate handle
 *  obj.includeResize = true|false  if (isEditable === true) show outlinebox + resize handle
 *  obj.includeOutline = true|false  show outlinebox
 *  obj.textLoc
 *  obj.textOffset  // offsetScreenPt
 *  obj.pts         // center of footprint or marker, rotation center
 *  obj.drawObjAry   // array of ShapeDataObj it contains
 *  obj.originalOutlineBox  // the 'original' outlinebox, is only recorded if the outline box around the footprint is in view
 *                        // the outlinebox object included in drawObjAry may not be the original (coult be becomes around 'center' or 'plotcenter')
 *  obj.isRotatable  //rotablable
 *  obj.isEditable   //resizable
 *  obj.isMovable    //movable
 *  obj.outlineIndex // handler starting index, outline box object position in drawObjAry
 *  obj.resizeIndex  //resize handler index in drawObjAry
 *  obj.rotateIndex  //rotate handler index in drawObjAry
 *  sequence: outlinebox (handleIndex) => (resizeIndex) => (rotateIndex)
 * @param sType
 * @param style
 * @returns {*}
 */


/**
 * convert 1-D size to either in arcsec or image pixel unit in case no projection is available
 * @param cc
 * @param size
 * @param unitType
 * @param resUnit output unit
 * @returns {{length: *, unit: *}}
 */


/**
 * generate handler box size and unit in either arcsec unit or image pixel unit in case no projection exists.
 * @param cc
 * @param boxSize
 * @param unitType
 * @returns {{size: *, unit: *}}
 */


/**
 * make drawObj for Marker with handlers or not. Marker is defined as a circle with 4 handlers at the corners
 * outline box is created
 * @param centerPt
 * @param width  image coordinate
 * @param height
 * @param isHandle
 * @param cc
 * @param text
 * @param textLoc
 * @param unitType
 * @returns {*}
 */


/**
 * make foopprint drawobj, create drawObj on all regions defined
 * outline box is created and included in the drawObjAry always, includeOutline is used to determine if it is drawn
 * @param regions   region defined in one footprint
 * @param centerPt  destination of center point (defaultly mapped from [0, 0] world coordinate)
 * @param isHandle  with rotate handle or not,
 * @param cc
 * @param text		text around the footprint
 * @param textLoc
 * @return footprint drawobj
 */


/**
 * collect drawObj contained in footprint or marker
 * @param drawObj
 * @param includeList fine the drawObj (outlineBox, resize handle or rotate handle) in the list
 * @returns {Array}
 */


/**
 * create outline box based on the drawObjs with some rotation angle
 * @param drawObj
 * @param cc
 * @param checkOutline
 * @returns {*}
 */


/**
 * update the resize handle, rotate handle, and outline box,  whichever is applied
 * @param drawObj
 * @param cc
 * @param handleList
 * @param upgradeOutline check if upgrade existing outline box from 'center' to 'original' or from 'plotcenter' to
 *                        'center' or 'original' if they are visible in viewport
 * @returns {*}
 */


/**
 * create outline by first trying to create the outline around all object, or around the center if the object
 * is oversized, or around the plot center if no corner is seen
 * stop creating the outline box around the center or the plot center if 'stopAt' is specified
 * @param fpCenter
 * @param outlineCenter
 * @param width
 * @param height
 * @param unitType
 * @param cc
 * @param sType
 * @param angle angle rotate on screen domain. reverse the angle on image domain
 * @param stopAt
 * @returns {*}
 */


/**
 * create resize handle on the corners of outline box
 * @param outlineBox
 * @param cc
 * @param rotAngle
 * @returns {*}
 */


/**
 * create rotate handle at prorper side of outline box by trying the right, top, left and bottom sides respectively
 * @param outlineBox
 * @param cc
 * @param rotAngle
 * @returns {*}
 */


/**
 * create outline box by checking if any corner is in view
 * @param centerPt
 * @param width
 * @param height
 * @param unitType
 * @param cc
 * @param angle
 * @returns {*}
 */


/**
 * find the drawObj inside the marker which is closest to the given screenPt (marker and the handlers)
 * @param screenPt
 * @param drawObj
 * @param cc
 * @returns {*}
 */


/**
 * update the color based on the setting in def for all drawing objects except center, resize & rotate handles
 * @param drawObj
 * @param def
 */


/**
 * draw the text attached with footprint drawobj by text drawing function in ShapeDataboj
 * @param drawObj
 * @param plot
 * @param def
 * @param ctx
 */


/**
 * update the footprint outline box once some object is clicked to be selected or relocated.
 * re-render the entire footprint in case the plot zoom changes or footprint on HiPS plot is relocated
 * @param drawObj
 * @param cc
 * @param bForced force to recalculate the drawObj from the original regions
 * @returns {*}
 */


/**
 * update the outline box after translation and rotation operation.
 * @param drawObj
 * @param cc
 * @param upgradeOutline
 * @param resetOutline  recompute the outline box from the original regions
 */


/**
 * update the translation information of the footprint or marker, store it in either world coordinate or image coordinate.
 * The computation is either made on image coordinate or originally defined regions (for HiPS)
 * @param drawObj
 * @param cc
 * @param apt
 * @param isSet set or incrment the translation
 */


/**
 * update object rotate angle
 * @param drawObj
 * @param plot
 * @param worldPt  center point to rotate around
 * @param angle
 * @param angleUnit
 * @param isSet set or increment the rotation angle
 * @returns {*}
 */


/**
 * translate marker or footprint
 *  - marker or non HiPS image: translate the marker/footprint by apt on image coordinate
 *  - HiPS: recompute the footprint per originally defined regions by translating the footprint center first
 * @param drawObj
 * @param plot
 * @param apt
 * @returns {*} an array of translated objects contained in drawObj
 */


/**
 * rotate a marker around worldPt by angle on image coordinate
 * @param drawObj
 * @param plot
 * @param dAngle  screen coordinate direction, in radian
 * @param worldPt
 * @returns {array} a array of rotated objects contained in drawObj
 */


/**
 * update marker object (main marker and outline box) per new size
 * @param markerObj
 * @param cc
 * @param newSize
 */


/**
 * update the text attached to the footprint object
 * @param drawObj
 * @param text
 * @param textLoc
 * @returns {*}
 */


/**
 * generate region description for marker or footprint
 * @param drawObj
 * @param plot
 * @param def
 * @returns {*}
 */


/**
 * Readout watcher defined the algorythm to drive the mouse readout. It does the following:
 *   - waits for a promise of a mouse event
 *   - Has two modes lockByClick, on or off
 *   - lockByClick off:
 *       - on mouse move compute and fire a mouse readout object
 *       - if mouse pauses (200 ms) and readout uses async, call the server for more data (the image pixel flux value)
 *       - if mouse still pause, fire a updated mouse readout object
 *   - lockByClick on:
 *       - on mouse click compute and fire a mouse readout object
 *       - if readout uses async, call the server for more data
 *       - if the position has not changed, fire a updated mouse readout object
 *
 */


/**
 * do wavelength readout if it has pixel level wl or if it is a not a cube image with plane wl info
 * @param plot
 * @param imagePt
 * @return {Object}
 */


/**
 *
 * @param {WebPlot} plot
 * @param {WorldPt} worldPt
 * @param {ScreenPt} screenPt
 * @param {ImagePt} imagePt
 * @return {Object}
 */


/**
 *
 * @param {WebPlot} plot
 * @param {WorldPt} worldPt
 * @param {ScreenPt} screenPt
 * @param {ImagePt} imagePt
 * @param {boolean} threeColor
 * @param {number} [healpixPixel] the healpix pixel for the current tile, only passed with HiPS
 * @param {number} [norder] the healpix pixel norder
 * @return {Object}
 */


/**
 * type {TableWatchFunc}
 * this saga does the following:
 *

 *
Waits until first fits image is plotted
 *
loads all the table that are catalogs
 *
Then loops:
 *

 *
waits for a table new table, update, highlight or select change and then updates the drawing layer
 *
waits for a new plot and adds any catalog
 *

 *

 * @param tbl_id
 * @param action
 * @param cancelSelf
 * @param params
 * @return {{tableManaged:boolean}}
 */


/**
 * return true if the point is not one the display
 * @param {PlotView} pv
 * @param {WorldPt|Point} wp
 * @param {boolean} force
 * @return {boolean}
 */


/**
 * recenter the image on the active row.
 *
 * for this to happen: autoScrollToHighlightedTableRow===true, the table must exist and have a center ra/dec,
 * the image much exist, and the image cannot be a MultiProductViewer image driven by a data product table.
 *
 * Therefore, types of image that recenter are usually pinned images or coverage images.
 *
 * @param {PlotView} pv PlotView to recenter
 * @param tbl_id the table id
 * @param force force a recenter under all cases
 */


/**
 * Action watcher callback: watch the tables and update coverage display
 * @callback actionWatcherCallback
 * @param tbl_id
 * @param action
 * @param cancelSelf
 * @param params
 * @param params.options read-only
 * @param params.sharedData read-only
 * @param params.sharedData.preparedTables
 * @param params.sharedData.tblCatIdMap
 * @param params.sharedData.preferredHipsSourceURL
 * @param params.paused
 */


/**
 *
 * @param {string} viewerId
 * @param {TableModel} table
 * @param {CoverageOptions} options
 * @param {string} tbl_id
 * @param preparedTable
 * @param preparedTables
 * @param usesRadians
 * @param {object} tblCatIdMap
 * @param {string} preferredHipsSourceURL
 * @param {string} preferredHipsSource360URL
 * @param {string} deletedTblId - only defined if a table has been deleted
 */


/**
 *
 * @param {string} plotId
 * @param {CoverageOptions} options
 * @param {TableData} table
 * @param {TableData|String} preparedTable
 * @param {string} drawOp
 * @param visibleMap - when added it is visible
 */


/**
 * look up a value from the CoverageOptions
 * @param {CoverageOptions} options
 * @param {string} key
 * @param {string} tbl_id
 * @return {*}
 */


/**
 * type {TableWatchFunc}
 * this saga does the following:
 *

 *
Waits until first fits image is plotted
 *
loads all the table that are catalogs
 *
Then loops:
 *

 *
waits for a table new table, update, highlight or select change and then updates the drawing layer
 *
waits for a new plot and adds any catalog
 *

 *

 * @param tbl_id
 * @param action
 * @param cancelSelf
 * @param params
 * @return {*}
 */


/**
 * find the plotId of a hips with the passed URL
 * @param url
 * @return {String} plotId
 */


/**
 * find plotId of active or first HiPS
 * @return {String} plotId
 */


/**
 * Action watcher callback: watch the tables with access_url column and update table column attributes for
 * table rendering which displays access_url column as a link.
 * @param tbl_id
 * @param action
 * @param cancelSelf
 * @param params
 * @return {*}
 */


/**
 * Reducer entry point. This function returns a reducer initialized to work with the passed band.
 * @param {Band} band
 * @return a reducer function. a standard type reducer function.
 */


/**
 *
 * Recompute the state. If there is a field value change then update the fields based on that.
 * If there is a replot or a init the update all the fields based on the current plot
 * @param fields
 * @param plottedRV
 * @param band
 * @param action
 * @return {*}
 */


/**
 * Sync the fields so that are consistent with the passed RangeValues object.
 * @param fields
 * @param rv
 */


/**
 * This function creates new 'lowerRange' field based on the 'lowerWhich' value. The min and max will be different
 * depending on what 'lowerWhich' is set to.
 * @param {object} fields - map of fields
 * @param {RangeValues} rv
 * @param {String} lowerWhich - field key for the type of lower range
 * @param {String} lowerRange - field key for lower range field
*/


/**
 * This function creates new 'upperRange' field based on the 'upperWhich' value. The min and max will be different
 * depending on what 'upperWhich' is set to.
 * @param fields
 * @param rv
 * @return {*}
 */


/**
 * Make a new RangeValue object from the field settings.
 * @param fields
 * @return {RangeValues}
 */


/**
 * Update all the fields from a RangeValues object.
 * @param fields
 * @param {RangeValues} rv
 */


/**
 * Reducer entry point. This function returns a reducer initialized to work with the passed band.
 * @param {Array.<Band>} bands
 * @return a reducer function. a standard type reducer function.
 */


/**
 * Recompute the state. If there is a field value change then update the fields based on that.
 * If there is a replot or a init the update all the fields based on the current plot
 * @param fields
 * @param plottedRVAry
 * @param bands
 * @param action
 * @returns {*}
 */


/**
 * Sync the fields so that are consistent with the passed RangeValues.
 * @param fields
 * @param {Array} rvAry
 */


/**
 * Make a new RangeValue object from the field settings.
 * @param fields
 * @return {Array.<RangeValues>}
 */


/**
 * Update all the fields from a RangeValues object.
 * @param fields
 * @param {Array.<RangeValues>} rvAry
 */


/**
 * representing the number into decimal or exponential format
 * @param {number} [num]
 * @param {number} [fractionDigits=7] fractional digits after the decimal point
 * @return {string}
 */


/**
 * tabularize the area statistics into summary and stats two sections for popup display
 * @param {object} wpResult
 * @param {object} cc
 * @returns { object } {statsSummary: array (for summary items), statsTable: array (for table rows)}}
 */


// attach image outline drawing layer on top of the cropped image, zoom-to-fit image and recenter image


/**
 * close any toolbar layers
 * @param exceptionKeys
 */


/**
 * Label for non-celestial coordinates readout item.
 * @param plotId
 */


/**
 * Count the number of cubes
 * @param {PlotView} pv
 * @return {number} the number of cubes, 0 if none
 */


/**
 /**
 *
 * @param {VisRoot} state
 * @param {Action} action
 * @param {Array.<PlotGroup>} plotGroupAry
 * @return {Array|null} new PlotViewAry or null it nothing is created.
 */


/**
 *
 * @param plotGroupAry
 * @param action
 * @return {Array|null} new PlotGroupAry or null if nothing is created.
 */


/**
 *
 * @param {PlotView} pv
 * @param {object} att
 * @param {boolean} toAll
 * @return {PlotView} new plotview object
 */


/**
 * @global
 * @public
 * @typedef {Object} ImageTile
 * @summary a single image tile
 *
 * @prop {number} width - width of this tile
 * @prop {number} height - height of this tile
 * @prop {number} index - index of this tile
 * @prop {string} url - file key to use in the service to retrieve this tile
 * @prop {number} x - pixel offset of this tile
 * @prop {number} y - pixel offset of this tile
 *
 */


/**
 *
 * @param {VisRoot} state
 * @param {Action} action
 * @return {VisRoot}
 */


/**
 *
 * @param {Array<PlotView>} plotViewAry
 * @param {PlotView|undefined} pv
 * @param {CoordinateSys} coordSys
 * @param {boolean} applyToGroup
 * @return {Array<PlotView>}
 */


/**
 * @param {VisRoot} state
 * @param {Action} action
 * @return {VisRoot}
 */


/**
 * Center on the FIXED_TARGET attribute or the center of the plot or specified center point
 * @param {Point|null|undefined} centerPt center point
 * @param {boolean} centerOnImage - only used if centerPt is not defined.  If true then the centering will be
 *                  the center of the image.  If false, then the center point will be the
 *                  FIXED_TARGET attribute, if defined. Otherwise it will be the center of the image.
 * @param {boolean} updateFixedTarget if true the PlotAttribute.FIXED_TARGET will but updated to this point
 * @return {Function} a new plot view
 */


/**
 *
 * @param {DrawLayerFactory} factory
 * @return {function} reducer
 */


/**
 * @param {string} plotId
 * @param {WebPlotRequest} req
 * @param {PVCreateOptions} pvOptions options for this plot view
 * @return  {PlotView}
 */


/**
 *
 * @param {WebPlotRequest} req
 * @param {PVCreateOptions} pvOptions
 * @return {PlotViewContextData}
 */


/**
 *
 * @param pv
 * @return {PlotView}
 */


/**
 *
 * @param {plotView} pv
 * @param nextIdx
 * @return {PlotView}
 */


/**
 * Replace the plotAry and overlayPlotViews into the PlotView, return a new PlotView
 * @param {PlotView} pv
 * @param {WebPlot[]} plotAry
 * @param {Array} overlayPlotViews
 * @param {ExpandType} expandedMode
 * @param {boolean} newPlot true, this is a new plot otherwise is is from a flip, rotate, etc
 * @return {PlotView}
 */


/**
 * create a copy of the PlotView with a new scroll position and a new view port if necessary
 * The scroll position is the top left visible point.
 * @param {PlotView|undefined} plotView the current plotView
 * @param {Point} newScrollPt  the screen point of the scroll position
 * @return {PlotView} new copy of plotView
 */


/**
 * scroll a plot view to a new screen pt, if positionLock is true then all the plot views in the group
 * will be scrolled to match
 * @param {VisRoot} visRoot
 * @param {string} plotId plot id to set the scrolling on
 * @param {Array} plotViewAry an array of plotView
 * @param {Array} plotGroupAry the plotGroup array
 * @param {ScreenPt} newScrollPt a screen point in the plot to scroll to
 * @return {Array.<PlotView>}
 */


/**
 * Create a new plotView that will wcs match the scroll position of the master plotView.
 * This function all all the safety checks for undefined plotview or plots. It is
 * always safe to call.
 * @param {WcsMatchType} wcsMatchType
 * @param {PlotView|undefined} masterPv - master PlotView
 * @param {PlotView|undefined} matchToPv - match to PlotView
 * @return {PlotView} a new version of matchToPv with the scroll position matching
 */


/**
 * Find a scroll point that the point puts the plot be scroll the to same wcs or target as the master plot
 * To use this function the plot view objects and the primary plot objects must all be defined.
 * @param {WcsMatchType} wcsMatchType
 * @param {PlotView} masterPv - master PlotView
 * @param {PlotView} matchToPv - match to PlotView
 * @return {ScreenPt} the screen point offset
 */


/**
 * make a function that will match the scroll position of a plotview to the source plotview
 * @param {PlotView} sourcePV the plotview that others will match to
 * @param {VisRoot} visRoot
 * @return {function} a function the takes the plotview to match scrolling as a parameter and
 *                      returns the scrolled matched version
 */


/**
 *
 * @param {WebPlot} plot
 * @param {{width: number, height: number}} viewDim
 * @return {{scrollWidth: number, scrollHeight: number}}
 */


/**
 *
 * @param {PlotView} plotView
 * @return {ScreenPt}
 */


/**
 * Return the scroll point for a PlotView that will place the given image point on the given device point.
 * or another way to say it:
 * Given a device point and an image point, return the scroll point the would make the two line up.
 * @param {PlotView|undefined} pv
 * @param {ImagePt|undefined} ipt - if this is not an image point it will be converted to one
 * @param {DevicePt} targetDevPtPos - the point on the device that the image
 * @return {ScreenPt} the scroll position the places the image point on to the device point
 */


/**
 * @param {PlotView} pv
 * @param {WorldPt} wpt
 * @param targetDevPtPos
 * @return {WorldPt}
 */


/**
 *
 * @param imageOverlayId
 * @param plotId plot id of image that is overlayed
 * @param {String} title
 * @param imageNumber
 * @param maskNumber
 * @param maskValue
 * @param {string} color the color, if overlay is a mask
 * @param drawingDef
 * @param {string} [relatedDataId] a related data id if one exist
 * @param {string} [fileKey] a file on the server
 * @return {OverlayPlotView}
 */


/**
 *
 * @param {WebPlot} plot
 * @param {WebPlotRequest} r the request
 * @return {String} the title
 */


/**
 *
 * @param {ImageContainer|Object|String} imageData the current image data or a html image object or the source of the
 *                                       of an image to load
 * @return {Promise} promise with new imageData
 */


/**
 * Draw one HiPS tile by breaking it into 2 triangle and draw each. This function follows the aladin's example
 *
 * @param ctx - canvas context
 * @param img - the image tile
 * @param {Array.<DevicePt>} cornersAry - array of points of the 4 corners to copy the image to on the destination canvas
 * @param {Number} tileSize - width/height of image tile
 * @param {DevicePt|{x:number,y:number}} offset - an offset point
 * @param {boolean} isMaxOrder
 * @param {number} norder
 * @param {number} desiredNorder
 */


/**
 * Reproject and draw the part of the image defined by triangle source point 0,1,2 to triangle pt 0,1,2 of the destination image
 *
 * This started with code from Aladin which it took from demo code http://www.dhteumeuleu.com/lab/image3D.html
 * it takes a triangle from a source image and maps to a triangle in the target image
 * I have modified it to use transformation-matrix-js since the triangle transform is well understood.
 * transformation-matrix-js is used to compute the affine transform to do the drawing
 *
 * This is effectively 3d triangle drawing without using web GL.
 *
 * @param ctx - canvas context
 * @param img - source image
 * @param {Point} offset an offset point, an offset into existing image of the source pt
 * @param {Point} s0 - source point 0
 * @param {Point} s1 - source point 1
 * @param {Point} s2 - source point 2
 * @param {Point} pt0 - destination point 0
 * @param {Point} pt1 - destination point 1
 * @param {Point} pt2 - destination point 2
 * @param {number} correction
 * @param {boolean} centerPtCorrection - in a 4 triangle case this should be false, you don't want to have correction * internal to the tile
 * todo - we we do 16 triangle we need more than a boolean to specify where the correction is applied
 */


/**
 * The object that can render a HiPS to the screen.
 * @param {{plotView:PlotView, plot:WebPlot, targetCanvas:Canvas, offscreenCanvas:Canvas,
 *          opacity:number, offsetX:number, offsetY:number}} screenRenderParams
 * @param totalCnt
 * @param isBaseImage
 * @param screenRenderEnabled
 * @param hipsColorOps
 * @param {boolean} isMaxOrder - true if the order drawing is max order
 * @param {number} norder
 * @param {number} desiredNorder
 * @return {Object}
 */


/**
         *
         * draw all tiles async (check cache or retrieve image and draw tile).
         * Any retrieved tiles will the added to the cache.
         * @param {Array.<HiPSDeviceTileData>} tilesToLoad
         * @param {WebPlot} plot
         */


/**
         *
         * draw all tiles immediately. Any tile not in cache will be ignored.
         * @param {Array.<HiPSDeviceTileData>} tilesToLoad
         * @param {WebPlot} plot
         */


/**
         *
         * @param {HiPSAllSkyCacheInfo} cachedAllSky
         * @param {Array.<HiPSDeviceTileData>} tilesToLoad
         */


/**
         * abort the last async draw, if last draw was sync, it is a noop
         */


/**
 * Return a function that should be called on every render to draw the image
 * @param {HTMLCanvasElement} targetCanvas
 * @return {*}
 */


/**
 * return a object with two functions drawTile
 * @param {PlotView} plotView
 * @param {WebPlot} plot
 * @param {HTMLCanvasElement} targetCanvas
 * @param {number} offsetX
 * @param {number} offsetY
 * @param {number} opacity
 * @param {{x:number,y:number,width:number,height:number}} tile
 */


/**
 * Return a function that should be called on every render to draw the image
 * @param targetCanvas
 * @param GPU
 * @return {*}
 */


/**
 * draw a transitional image when scrolling or zooming.  The transitional image will be overlaid with the final image.
 * @param fov
 * @param centerWp
 * @param targetCanvas
 * @param plot
 * @param plotView
 * @param norder
 * @param transitionNorder
 * @param hipsColorOps
 * @param opacity
 * @param finalTileToLoad
 * @param colorMode
 */


/**
 *
 * @param p
 * @param p.targetCanvas
 * @param p.offscreenCanvas
 * @param p.plot - note this could the main plot or an overlay plot
 * @param p.plotView
 * @param p.norder
 * @param p.hipsColorOps
 * @param p.tilesToLoad
 * @param p.useAllSky
 * @param p.drawAllSkyOnlyIfCached
 * @param p.drawAllSkyOnlyIfCached
 * @param p.opacity
 * @param p.drawTiming
 * @param p.screenRenderEnabled
 * @param {boolean} [p.isMaxOrder] true if this norder is the max order
 */


/**
 * first look for an allsky image with the correct color, it not found look at see if we have the base allsky image
 * if not found return, if we have the base one then change the color and that version to the cache, then return it
 * @param allSkyURL
 * @param {number} ctId
 * @param {number} bias
 * @param {number} contrast
 * @param hipsColorOps
 * @return {HiPSAllSkyCacheInfo|undefined}
 */


/**
 * action creator of REGION_CREATE_LAYER, create drawing layer based on region file or array of region description
 * @param rawAction
 * @returns {Function}
 */


/**
 * parse array of region description in json or ds9 format and create drawing layer based on parsed results
 * @param regionAry
 * @param title
 * @param drawLayerId
 * @param plotId
 * @param selectMode
 * @param dataFrom
 */


/**
 * action creator for REGION_DELETE_LAER, remove drawing layer of regions
 * @param rawAction
 * @returns {Function}
 */


/**
 * action creator for REGION_ADD_ENTRY or REGION_REMOVE_ENTRY, add or remove regions from drawing layer
 * @param rawAction
 * @returns {Function}
 */


/**
 * create region DrawObj if not exist in region object array
 * @param crtRegions
 * @param aRegionObj
 * @returns {null}
 */


/**
 * remove Region object from Region array if existing
 * @param crtRegions
 * @param aRegionObj
 * @returns {{index: *, regions: *}}
 */


/**\
 * check if two Region object are the same
 * @param region1
 * @param region2
 * @returns {*}
 */


/**
 * check how many Region in an array are without property, 'key'
 * @param key
 * @param rgAry
 * @returns {number}
 */


/**
 * check if two Regions are at the same position
 * @param region1
 * @param region2
 * @returns {boolean}
 */


/**
 * check if two Regions are with the same size or dimension
 * @param region1
 * @param region2
 * @returns {boolean}
 */


/**
 * check if two Regions are with the same angle
 * @param region1
 * @param region2
 * @returns {boolean}
 */


/**
 * union option property from two Regions
 * @param optionSet1
 * @param optionSet2
 * @returns {Array}
 */


/**
 * check two Regions are with the same options
 * @param region1
 * @param region2
 * @returns {boolean}
 */


/**
 * make region descript array from plot DrawObj of all visible DrawLayer
 * @param plot
 * @param bSeperateText denote to not use default text loc setting
 */


/**
 * region description: [<J2000>|image|physical]; [point x y | box x y w h a | ellipse x y r1 r2 a |
 *                                                line x1 y1 x2 y2 | text x y | circle x y r]
 * @param regionType
 * @param cc
 * @param ptAry  position point (x, y) array
 * @param regionDimAry  dimenstion (r1, r2) or (width, height) array
 * @param regionValAry  value array (r1, r2, ...) for annulus
 * @param isAngle       if angle is needed
 * @param angle
 * @returns {*}         region description string
 */


/**
 * make drawObj based on region type
 * @param regionAry Region array
 * @returns {*}     drawing object array
 */


/**
 * make DrawObj for one region
 * @param regionObj
 * @returns {Array}
 */


/**
 * convert RegionPointType to DrawObj DrawSymbol
 * @param ptype
 * @returns {*}
 */


/**
 * add addition property to DrawObj based on selected RegionOptions properties
 * @param rgPropAry
 * @param rgOptions
 * @param dObj
 */


/**
 * produce DrawObj for region circle
 * @param r
 * @param wp
 * @param options
 * @param propChkAry
 * @returns {*}
 */


/**
 * produce DrawObj array for region annulus, get the circle from the outmost first
 * @param regionObj
 * @returns {*}
 */


/**
 * make one drawobj for box with ratote angle, makeRectangleByCenter is used
 * @param w  width
 * @param h  height
 * @param a rotation angle
 * @param wp center of box
 * @param options region properties
 * @param propChkAry property cheeck list
 * @param isOnWorld
 * @returns {*}
 */


/**
 * make DrawObj for one box with angle
 * @param regionObj
 * @returns {Object[]}
 */


/**
 * make DrawObj array for region box annulus, get the outmost box first
 * @param regionObj
 * @returns {*}
 */


/**
 * make DrawObj for region line
 * @param pt1
 * @param pt2
 * @param options
 * @param propChkAry
 * @returns {*}
 */


/**
 * make DrawObj array for region polygon
 * @param regionObj
 * @returns {*}
 */


/**
 * make one drawobj for ellipse with ratote angle, makeEllipse is used
 * @param r1  radius1
 * @param r2  radius2
 * @param a rotation angle
 * @param wp center of ellipse
 * @param options region properties
 * @param propChkAry property cheeck list
 * @param isOnWorld
 * @returns {*}
 */


/**
 * make DrawObj for one ellipse with angle
 * @param regionObj
 * @returns {Object[]}
 */


/**
 * make DrawObj array for region ellipse annulus, get the outmost ellipse first
 * @param regionObj
 * @returns {*}
 */


/**
 * make DrawObj for region point
 * @param regionObj
 * @returns {Object[]}
 */


/**
 * make DrawObj for region text
 * @param regionObj
 * @returns {Object[]}
 */


/**
     * parse region description for server generated JSON
     * @param regionData
     * @returns {null}
     */


/**
     * @param regionData
     * @param bAllowHeader
     * @param relocatable
     * @param stopAt
     * @returns {array} an array of Region object
     */


/**
     * parsePart parses the region data of JSON result (one item from RegionData array)
     * @param regionStr each string is either like coordinate;region_description or region_descrption
     * @param index  line number shown in message
     * @param globalOptions
     * @param bAllowHeader
     * @returns {makeRegion} including makeRegion().message to contain error message if there is
     */


/**
     * seperate region description elements and extract text string
     * @param regionDes
     * @returns {Array}
     */


/**
     * parse region description based on the region type
     * @param regionType
     * @param params
     * @param regionCsys
     * @param pointType
     * @returns {*}
     */


/**
     * process region poisition coordinate
     * @param coordSys
     * @param xStr
     * @param yStr
     * @returns {*}
     */


/**
     * refactor the region coordinate value based on the coordinate system the region is defined at
     * @param rvX
     * @param rvY
     * @param coordsys
     * @returns {*}
     */


/**
     * parse coordinate string into value and unit, convert sexigesimal into degree
     * @param vstr
     * @param coordSys
     * @param vType  lon or lat
     * @returns {*}
     */


// the degree will be further converted to to in image or pixel unit in refactorRegionValueUnit


/**
     * convert angle value based on the suffixed unit if there is
     * @param vstr
     * @returns {null}
     */


/**
     * convert value of position based on the relevant unit
     * @param xStr
     * @param yStr
     * @param coordSys
     * @returns {Array}
     */


/**
     * convert value of dimension based on the relevant unit
     * @param vStr
     * @param coordSys
     * @returns RegionValue
     */


/**
     * parse the region options
     * @param {string} optionStr
     * @param {int} include
     * @param {object} rgOps
     * @param {object} rgCsys
     * @returns {*}
     */


/**
     * parse point property
     * @param ptStr
     * @param option
     * @returns {*}
     */


/**
     * parse font property
     * @param fontStr
     */


/**
 * color bar Action creator
 * @param rawAction
 * @return {Function}
 */


/**
 * @param rawAction
 * @return {Function}
 */


/**
 * @param {VisRoot} vr
 * @param {String} plotId
 */


/**
 * Add add a image outline to some HiPS display and attempts to zoom to the same scale.
 * @param {PlotView} pv
 * @param {Array.<string>} hipsPVidAry
 */


/**
 * @param {PlotView} pv
 * @param {PlotView} masterPv
 */


/**
 *
 * @param {PlotView} pv
 * @param {String} plotId
 * @param {Enum} matchType
 * @return {WorldPt}
 */


/**
 * zoom Action creator,
 * @param rawAction
 * @return {Function}
 */


/**
 * look at the userZoomType parameter a return the right zoom level plus some information about how to zoom
 * @param {VisRoot} visRoot
 * @param {PlotView} pv
 * @param {UserZoomTypes} userZoomType
 * @param {number} payloadLevel
 * @param {number} [upDownPercent] value between 0 and 1 - 1 is 100% of the next step up or down
 * @return {{level: number, validParams: boolean}}
 */


/**
 * Zoom the image or hips.
 * First check to see it the plot should be converted between HiPS and image
 *
 * @param dispatcher
 * @param {WebPlot} plot
 * @param {number} zoomLevel
 * @param {boolean} zoomLockingEnabled
 * @param {UserZoomTypes} userZoomType
 * @param {DevicePt} devicePt
 * @param {Function} getState
 */


/**
 * Only used during parsing, not for general use
 * @param {WebPlotInitializer} plotCreate
 * @return {number} plane index or -1 if not a cube plane
 */


/**
 * @param {Array.<WebPlotInitializer>} plotCreate
 * @return {Array.<CubeCtx>}
 */


/**
 * readds the data into each plotCreate from the plotCreateHeader.
 * The data in the header is replicated in each plot and was clear for network transfer
 * efficiency. This optimization is very import for large cubes.
 * Note- plotCreate is modified in place plotCreate will be changed, no new object is created.
 * @param plotCreateHeader
 * @param plotCreate
 */


/**
 *
 * @param dispatcher
 * @param {object} payload the payload of the original action
 * @param {object} result the result of the search
 */


/**
 * @param {WebPlot} plot
 */


/**
 *
 * @param {String[]} plotIdAry
 */


// 9 arcsec - minimum fov for initial size


/**
 * convert to a image defined in  hipsImageConversion
 * @param {PlotView} pv
 * @param {boolean} tryCenterBySelectedObj - if the field of view is large and convert to image is selected then try to
 *             choose and image center that is the selected object of the associated table.
 */


/**
 * This function has a lot of side effects, it modified wpRequest and dispatch drawing
 * @param pv
 * @param wpRequest
 */


/**
 * This function will convert between HiPS and FITS or FITS and Hips depend on hipsImageConversion settings and zoom
 * direction.
 * @param {PlotView|undefined} pv
 * @param {number} [prevZoomLevel] - previous zoom level
 * @param {number} [nextZoomLevel] - next zoom level
 * @return {boolean}
 */


/**
 *
 * @param rawAction
 * @return {Function}
 */


/**
 * create lsst footprint by checking if a footprint source catalog, an lsst image file or footprint data is send
 * - if an image file is set, load the image and then load the footprint file (table) if there is and get the footprint
 * data from the loaded file (table)
 * - if a footprint file is set, load the footpriont file (table) and then get the footprint data from the loaded table
 * - create the drawlayer per footprint data.
 * @param action
 * @returns {Function}
 */


/**
 *
 * @param {String} plotImageId
 * @param plotStateSerialized
 * @param plotState
 * @param {number} dataWidth
 * @param {number} dataHeight
 * @param {boolean} mask
 * @param {number} maskBits
 * @param {String} cmdSrvUrl
 * @param {String} dataCompress - should be 'FULL' or 'HALF' or 'QUARTER'
 * @param {boolean} veryLargeData - if true and dataCompress is 'QUARTER' never request full size
 * @return {Promise<StretchByteDataResults>}
 */


/**
 * color change needs to do the following
 *   - clear the raw data tiles
 *   - set the color in the plot state
 * @param {string} plotImageId
 * @param {number} colorTableId
 * @param {boolean} threeColor
 * @param {number} bias
 * @param {number} contrast
 * @param {boolean} bandUse
 * @param {PlotState} plotState
 * @param {string} rootUrl
 * @return {Object}
 */


/**
 *
 * @param {number} dataWidth
 * @param {number} dataHeight
 * @param {String} dataCompress - should be 'FULL' or 'HALF' or 'QUARTER'
 * @param rgbIntensity
 * @return {RawTileData}
 */


/**
 *
 * @param {number} x
 * @param {number} y
 * @param {number} width
 * @param {number} height
 * @return {RawTileData}
 */


/**
 *
 * @param {ImageBitmap|HTMLCanvasElement|ArrayBuffer} buffer
 * @param {number} width
 * @param {number} height
 * @return {HTMLCanvasElement}
 */


/**
 *
 * @param plot
 * @param colorTableId
 * @param bias
 * @param contrast
 * @param bandUse
 * @param onComplete function to call with rawData object when done, note this call will only happen if is is not overridden by another call
 * @return {Promise<ChangeColorResults>}
 */


/**
 * color change needs to do the following
 * @param {WebPlot} plot
 * @param {number} colorTableId
 * @param {number} bias
 * @param {number} contrast
 * @param bandUse
 * @return {ChangeColorResults}
 */


/**
 * load the stretch data from the server for a given stretch parameters. The loading will determine how much it compresses
 * this data it could be QUARTER, HALF, or FULL
 * @param pv
 * @param plot
 * @param dispatcher
 * @return {Promise<void>}
 */


/**
 * load the stretch data again if it is either QUARTER or HALF, if it is already FULL then return
 * @param {String} plotId
 * @param dispatcher
 * @param {boolean} secondTry - true if call recursively
 * @return {Promise<void>}
 */


/**
 *
 * @param {String} reqId - requestId
 * @param {String} plotId
 * @param {WebPlot|undefined} plot
 * @param {Number} waitTime
 * @param {String} dataCompress - should be 'FULL' or 'HALF' or 'QUARTER'
 * @param {String} workerKey
 * @param {function} dispatcher
 * @return {Promise<boolean>}
 */


/**
 *
 * @param {String} workerKey
 * @param {WebPlot} plot
 * @param {Object} loadingOptions
 * @param {String} loadingOptions.dataCompress- should be 'FULL' or 'HALF' or 'QUARTER'
 * @param {boolean} loadingOptions.backgroundUpdate
 * @param {boolean} loadingOptions.checkForPlotUpdate
 * @param {Object|undefined} [maskOptions]
 * @param {String} maskOptions.maskColor
 * @param {Number} maskOptions.maskBits
 * @return {Promise<{success:boolean, fatal: boolean}>}
 */


/**
 * @param {WebPlot} plot
 * @param {{rawTileDataGroup:RawTileDataGroup, plotStateSerialized:string}} stretchResult
 * @param {number} originalColorTableId
 * @return {Promise<boolean>}
 */


/**
     * Create a mask canvas tile
     * @param {String} maskColor
     * @param pixelData - each byte in pixelData represents 8 pixels, so the data is compressed into bits
     * @param {number} width
     * @param {number} height
     * @return {HTMLCanvasElement}
     */


/**
 *
 * @param {String} plotImageId
 * @param {String} workerKey
 * @return {WorkerAction}
 */


/**
 *
 * @param {WebPlot} plot
 * @param plotState
 * @param {Object|undefined} maskOptions
 * @param {String} maskOptions.maskColor
 * @param {Number} maskOptions.maskBits
 * @param {String} dataCompress - should be 'FULL' or 'HALF' or 'QUARTER'
 * @param {boolean} veryLargeData
 * @param {String} workerKey
 * @return {WorkerAction}
 */


/**
 *
 * @param ctx
 * @param {number} zf
 * @param {Array.<RawTileData>}rawTileDataAry
 * @param {number} x
 * @param {number} y
 * @param {number} width
 * @param {number} height
 * @param {String} dataCompress - should be 'FULL' or 'HALF' or 'QUARTER'
 */


/**
     * Toggle the bits of this mask in the given argument.
     * @param  mask  value in which to toggle the bits
     * @return the updated value
     */


/**
     * Clear the bits of this mask in the given argument.
     * @param  mask  value in which to unset the bits
     * @return the updated value
     */


/**
     * Return a boolean array indicating where any mask bits are set.
     * @param  mask  array of values in which to test the mask
     * @return true where any bit is set, for each element
     */


/**
     * Convenience method for creating a combination mask by anding the input masks. This mask can
     * then be used to test if all of the mask bits it contains are set.
     * @param masks individual input masks
     * @return a combined mask with all the input bits sets
     * @throws NullPointerException if the input is null.
     */


/**
     * Convenience method for creating a combination mask by oring the input masks. This mask can
     * then be used to test if any of the mask bits it contains are set.
     * @param masks individual input masks
     * @return a combined mask with all the input bits sets
     * @throws NullPointerException if the input is null.
     */


/**
     * Count the bits that are set in an integer/mask. This method also returns the index of the MSB.
     * @param n the input
     * @return a two-element array containing:
     */


/**
 * CDL_ZSCALE -- Sample the image and compute optimal Z1 and Z2 values.
 *
 * @param float1d image data to be sampled
 * @param nx image dimensions
 * @param ny
 * @param bitpix bits per pixel
 * @param contrast adj. to slope of transfer function
 * @param opt_size desired number of pixels in sample
 * @param len_stdline optimal number of pixels per line
 * @param blank_value blank value from FITS header
 * @return {{z1:number,z2:number}}
 */


/** sampleImage -- Extract an evenly gridded subsample of the pixels from
 * a two-dimensional image into a one-dimensional vector.
 *
 * @param float1d
 * @param nx
 * @param ny
 * @param optimal_size
 * @param len_stdline
 * @param blank_value
 * @return {{npix,sample}}
 */


/** subSample -- Subsample an image line.  Extract the first pixel and
 * every "step"th pixel thereafter for a total of npix pixels.
 */


/** fitLine -- Fit a straight line to a data array of type real.  This is
 * an iterative fitting algorithm, wherein points further than ksigma from the
 * current fit are excluded from the next fit.  Convergence occurs when the
 * next iteration does not decrease the number of pixels in the fit, or when
 * there are no pixels left.  The number of pixels left after pixel rejection
 * is returned as the function value.
 *
 * @param {Float32Array} data
 * @param npix
 * @param krej
 * @param ngrow
 * @param maxiter
 * @return {{zstart: number, zslope: number, ngoodpix: number}}
 */


/*
 * flattenData -- Compute and subtract the fitted line from the data array,
 * returned the flattened data in FLAT.
 * @param data
 * @param x
 * @param npix
 * @param z0
 * @param dz
 * @return {Float32Array}
 */


/** computeSigma -- Compute the root mean square deviation from the
 * mean of a flattened array.  Ignore rejected pixels.
 * @param {Array.<Number>} a - flattened data array
 * @param {Uint8Array} badpix - bad pixel flags (!= 0 if bad pixel)
 * @param npix
 * @return {{sigma: number, mean: number, ngoodpix: number}}
 */


/** rejectPixels -- Detect and reject pixels more than "threshold" greyscale
 * units from the fitted line.  The residuals about the fitted line are given
 * by the "flat" array, while the raw data is in "data".  Each time a pixel
 * is rejected subtract its contributions from the matrix sums and flag the
 * pixel as rejected.  When a pixel is rejected reject its neighbors out to
 * a specified radius as well.  This speeds up convergence considerably and
 * produces a more stringent rejection criteria which takes advantage of the
 * fact that bad pixels tend to be clumped.  The number of pixels left in the
 * fit is returned as the function value.
 *
 * @param data - raw data array
 * @param flat - flattened data array
 * @param normx - normalized x values of pixels
 * @param badpix - bad pixel flags (!= 0 if bad pixel)
 * @param npix
 * @param sumxsqr
 * @param sumxz
 * @param sumx
 * @param sumz - matrix sums
 * @param threshold - threshold for pixel rejection
 * @param ngrow - number of pixels of growing
 * @return {{sumxz: *, sumz: *, sumx: *, ngoodpix: number, sumxsqr: *}}
 */


// todo - the color id is not longer in plot state it is in plot


/**
 *
 * @param {Object} payload
 * @return {Promise<{Object}>}
 */


/**
 *
 * @param {Float32Array} float1d
 * @param imageTileData
 * @param processHeader
 * @param histogram
 * @param {RangeValues} rangeValues
 * @return {RawTileData} return a new version of RawTileData what is populated with the stretch data array(s)
 */


/**
 * UNTEST, I am not sure it should even be on the client
 * @param float1d
 * @param imageTileData
 * @param processHeader
 */


/**
 * A pixel is a cell or small rectangle which stores the information the computer can handle. A discrete pixels make the map.
 * Each pixel store a value which represents the color of the map.
 * Byte image is the pixel having a value in the range of [0, 255].  One byte has 8 bit.  The stretch algorithm is able to convert
 * some invisible pixel value to become recognizable.
 * There are several stretch algorithm: liner, log, log-log etc.  Using those technique to calculate new pixel values.  For example:
 * Suppose you have a certain image in which the values range from 55 to 103. When this map is stretched linearly to output range 0 to
 * 255: the minimum input value 55 is brought to output value 0, and maximum input value 103 is brought to output value 255, and all
 * other values in between change accordingly (using the same formula). As 0 is by default displayed in black, and 255 in white, the
 * contrast will be better when the image is displayed.
 *
 * @param {Number} startPixel (tile info) start pixel in each line
 * @param {Number} lastPixel (tile info) end pixel in each line
 * @param {Number} startLine (tile info) start line
 * @param {Number} lastLine (tile info) end line
 * @param {Number} naxis1
 * @param {HistogramData} hist
 * @param {Number} blank_pixel_value blank pixel value
 * @param {Float32Array} float1dArray
 * @param {Uint8Array} pixeldata
 * @param {RangeValues} rangeValues
 * @param {Number} slow
 * @param {Number} shigh
 */


/**
 * add a new stretch method to do the mask plot
 * @param startPixel (tile info) start pixel in each line
 * @param lastPixel (tile info) end pixel in each line
 * @param startLine (tile info) start line
 * @param lastLine (tile info) end line
 * @param naxis1 number of pixels in a line
 * @param blank_pixel_value blank pixel value
 * @param {Float32Array} float1dArray
 * @param {Uint8Array} pixeldata
 * @param pixelhist
 * @param {Array.<ImageMask>} lsstMasks
 */


/**
     * Routine to determine accurate position for pixel coordinates
     * returns 0 if successful otherwise 1 = angle too large for projection;
     * based on amdpos() from getimage
     *
     * @param xpix x pixel number  (RA or long without rotation)
     * @param ypix y pixel number  (dec or lat without rotation)
     * @param hdr
     */


/**
     * ****************************************************************************
     * Module:                                                                     *
     *    amdinv                                                                   *
     *                                                                             *
     * File:                                                                       *
     *    astrmcal.c                                                               *
     *                                                                             *
     * Description:                                                                *
     *    Computes the x,y position on the plate from the right ascension and      *
     *    declination using the inverse of the CALOBCC solution. Newton's method   *
     *    is used to iterate from a starting position until convergence is         *
     *    reached.                                                                 *
     *                                                                             *
     * Return Value:                                                               *
     *    none                                                                     *
     *                                                                             *
     * Arguments:                                                                  *
     *                                                                             *
     * @param ra The right ascension of the coordinates to convert to x-y.        *
     * @param dec The declination of the coordinates to convert to x-y.           *
     * @param hdr HEADER, Reference                                               *
     *             Structure with header information.                              *
     *       mag                                                                   *
     *          float, Value                                                       *
     *             Magnitude for the calibration solution.                         *
     *       col                                                                   *
     *          float, Value                                                       *
     *             Color for the calibration solution.                             *
     *    Output Arguments:                                                        *
     *       x                                                                     *
     *          float, Reference                                                   *
     *             Result x position.                                              *
     *       y                                                                     *
     *          float, Reference                                                   *
     *             Result y position.                                              *
     *                                                                             *
     * History:                                                                    *
     *    Created    : 07-MAY-90 by R. White,                                      *
     *       Converted from GASP IDL routine to Fortran.                           *
     *    Delivered  : 30-JUL-91 by R. White,                                      *
     *       Converted from Fortran to C.                                          *
     *                                                                             *
     *    Updated    : 13-AUG-93 by J. Doggett,                                    *
     *       Adopted into software used to facilitate the accessing of data from   *
     *          the CD-ROM set of the Digitized Sky Survey.                        *
     *    Updated    : 14-DEC-93 by J. Doggett,                                    *
     *       Modified to reflect change in calling sequence to traneqstd function. *
     *    Redelivered: 01-MAR-94 by J. Doggett,                                    *
     *       GetImage Version 1.0                                                  *
     *******************************************************************************
     * @param useProjException when the is a failure: true throw exception, false return null
     */


/******************************************************************************
* Module:                                                                     *
*    traneqstd                                                                *
*                                                                             *
* File:                                                                       *
*    astronmy.c                                                               *
*                                                                             *
* Description:                                                                *
*    Routine to convert RA and Dec in radians to standard coordinates on a    *
*    plate.                                                                   *
*                                                                             *
* Return Value:                                                               *
*    none                                                                     *
*                                                                             *
* Arguments:                                                                  *
*                                                                             *
*    Input Arguments:                                                         *
*       plt_center_ra                                                         *
*          double, Value                                                      *
*             Plate center right ascension in radians                         *
*       plt_center_dec                                                        *
*          double, Value                                                      *
*             Plate center declination in radians                             *
*       object_ra                                                             *
*          double, Value                                                      *
*             Input right ascension in radians.                               *
*       object_dec                                                            *
*          double, Value                                                      *
*             Input declination in radians.                                   *
*    Input/Output Arguments:                                                  *
*       none                                                                  *
*    Output Arguments:                                                        *
*       Object_Xi                                                             *
*          double, Reference                                                  *
*             Output xi standard coordinate in arcseconds.                    *
*       Object_Eta                                                            *
*          double, Reference                                                  *
*             Output eta standard coordinate in arcseconds.                   *
*                                                                             *
* History:                                                                    *
*    Created    : 07-MAY-90 by R. White,                                      *
*       Converted to Fortran from IDL routine.                                *
*    Delivered  : 30-JUL-91 by R. White,                                      *
*       Convert from Fortran to C.                                            *
*                                                                             *
*    Updated    : 13-AUG-93 by J. Doggett,                                    *
*       Adopted into software used to facilitate the accessing of data from   *
*          the CD-ROM set of the Digitized Sky Survey.                        *
*    Updated    : 14-DEC-93 by J. Doggett,                                    *
*       Modified to take plate center coordinates explicitly as arguments     *
*          rather than from the plate header.                                 *
*    Redelivered: 01-MAR-94 by J. Doggett,                                    *
*       GetImage Version 1.0                                                  *
******************************************************************************/


/**
 * 	Correct projection plane coordinates for field distortion;
 * 	Distortion coefficients pv1, pv2
 * @param x
 * @param y
 * @param pv1
 * @param pv2
 * @return {{xprime: *, yprime: *}}
 */


/**
 * User world coordinates determine if a point is in a rectangle,
 * This function will create a transformation for the test. It does not require a plot
 * @param {Array.<WorldPt>} wpAry - Point that make up the rectangle, array length should be 4
 * @param {WorldPt} testWp
 * @return {boolean} true if the world point in the rectangle
 */


/**
 *  compute the distance between two positions (lon1, lat1)
 *  and (lon2, lat2), the lon and lat are in decimal degrees.
 *  the unit of the distance is degree
 * @param {number} lon1
 * @param {number} lat1
 * @param {number} lon2
 * @param {number} lat2
 * @return {number}
 */


/**
 *
 * @param celref - the contents of this array is modified, todo - in the future this should be part of the return
 * @param euler - the contents of this array is modified, todo - in the future this should be part of the return
 * @param useProjException
 * @return {boolean}
 */


/**
 * Recursive linear interpolation:
 * start from the last coordinate, replace index array with the two that are necessary to find Y.
 * @param indexDataArr indexing vectors
 * @param coordData multi-d coordinate data array
 * @param psi_ms intermediate pixel coordinates
 * @param nprocessed the number of processed coordinates
 * @returns {number|*}
 */


/**
 * Get spectral coordinate value using linear interpolation in one dimension case.
 * @param indexData
 * @param coordData
 * @param psi_m  intermediate pixel coordinate along axis m
 * @returns {number|*}
 */


/**
 * Check if array is monotonically increasing or decreasing.
 * @param intArray
 * @returns {number}  1 for increasing, -1 for decreasing, 0 for non-monotonic
 */


/**
 *
 * @param {FitsHeader} header
 * @param {String} altWcs
 * @param {FitsHeader} zeroHeader
 * @param {Array.<WavelengthTabRelatedData>} wlTableRelatedAry
 * @param {boolean} reprojectedWcs
 * @return {SpectralWCSData|undefined}
 */


/**
 * Get indices of CTYPEs that we need to preserve: all and those requiring table lookup algorithm.
 * @param parse
 * @param {String} altWcs alternate WCS character
 * @param supportedCoordTypes list of the supported coordinate type codes
 * @returns {{iCtypeSupported: Array.<int>, iCtypeTab: Array.<int>}} indices of the supported coordinates and those requiring TAB algorithm
 */


/**
 * Check if spectral coordinates form a non-separable group.
 * @param {Array.<SpectralCoord>} spectralCoords
 * @returns {boolean} True if the coordinates form non-separable TAB group
 */


/**
 * Get parameters that can be relevant to multiple spectral coordinates in a WCS.
 * @param parse
 * @param altWcs
 * @returns {{nAxis: int, restWAV: number, r_j: Array.<int>, N: int}}
 */


/**
 *
 * Reference:  A&A 395, 1061-1075 (2002) DOI: 10.1051/0004-6361:20021326
 * Representations of world coordinates in FITS E. W. Greisen1 - M. R. Calabretta2
 * paper,  the CD_ij is for the older FITS header. The newer FITS header has PC only.
 *
 * This method is checking the pc_ij and r_j array.  If any of the values are undefined,
 * the default are assigned.  The default values are defined as following based on the reference
 * paper above:
 *
 * PC_ij: an array defined in the FITS header. Fhe size of the dimension is N.  N is defined by
 *  WCSAXES or naxis
 *   i: the wcsaxes's value, if the wcsaxes = 2, then i=2
 *   j: 0, ...N
 *   If any of the PC_ij is not defined in the header, the following default is assigned:
 *   1.  PC i_j =    1.0 when i = j
 *   2.  PC i_j = 0.0 when i!=j
 *
 *  If instead of using PC, CD is used, the following default is assigned:
 *  CD i_j    0.0  NOTE: CD i_j's default is different from PC i_j
 *
 *
 *  r_j: An array of the CRPIX values, the size of the dimension is N.  N is defined by
 *  WCSAXES or naxis
 *  j: 0,...N
 *
 *  Default values:
 *   if r_j  = value of CRPIXj, if it is not defined, the default value is 0.0
 *
 * @param inArr
 * @param keyRoot
 * @param which
 * @param N
 * @returns {Array}
 */


//this is to implement the wavelength independently to verify the wavelength implementation


/**
 * create a utc moment
 * @param str
 * @returns {Object} a moment
 */


/**
 * compare times in Moment or string
 * @param time1
 * @param time2
 */


/**
 * convert MJD string to ISO string
 * @param {String} mjdVal
 */


/**
 * validate time in moment or date-time string format
 * @param mVal
 * @param nullAllowed allow empty string
 * @returns {{valid: boolean, value: string, moment: Moment, message: string}}
 */


/**
 * validate MJD range
 * @param tStr
 * @param nullAllowed allow empty string
 * @returns {{valid: boolean, value: *, message: string}}
 */


/**
 * Return the min and max of the exposure range, If min or max not specified then return undefined for that one. Result
 * object includes a boolean if min and greater than max
 * @param {FieldGroupField} timeMinField
 * @param {FieldGroupField} timeMaxField
 * @returns {{minValue: string, maxValue: string, minGreaterThanMax: boolean, isoRange: number[], mjdRange: String[]}}
 */


/**
 *
 * @param objName
 * @param resolver
 * @return {{p: Promise<unknown>, aborter: aborter}}
 */


// 7 seconds - fetch will be aborted after timeout


/**
 * Returns the overrides portion of JoyUI's theme.
 * This will be used to extend(extendTheme) JoyUI's default theme.
 *
 * To customize Firefly's theme, start with the defaultTheme.  Then, update or add as needed.
 * Next, assign the customized theme to the application options.  e.g. firefly.theme.customized = () => ({<custom-theme>})

 * @return {object}
 */


/**
 * handle submit for an existing table
 * @param request
 * @param setUploadInfo
 * @param {DefaultColsEnabled} defaultColsEnabled
 * @param setLoading
 * @returns {boolean}
 */


/**
 * Return the default cols to be selected for the uploaded table based on colTypes and colCount
 *
 * @param columns
 * @param colTypes comes from {@link DefaultColsEnabled}
 * @param colCount comes from {@link DefaultColsEnabled}
 * @returns defaultCols
 */


/**
 * Set use to true or false for column entries to help set default selected columns for uploaded table
 *
 * @param columns
 * @param {DefaultColsEnabled} defaultColsEnabled
 * @returns columnsSelected
 */


/**
 * Display the upload table chooser popup panel
 *
 * @param setUploadInfo
 * @param groupKey
 * @param {DefaultColsEnabled} defaultColsEnabledObj if this is non-empty, it will be used to replace the default selection of the uploaded table cols
 */


/**
 *
 * @param csys coordinate system
 * @return string
 */


/**
 *
 * @param wp WorldPt
 * @return String
 */


/**
 *
 * @param wp world point
 * @returns {*}
 */


/**
 *
 * @param {String} tbl_id
 * @return {QueryAnalysis} - the description of all the searches to do for this table
 */


/**
 * Do all the searches defined
 * @param request
 * @param siaConstraints
 * @param {QueryAnalysis} qAna
 * @param primaryFdAry
 * @param idx
 * @param {object} extraMeta            // additional table meta to include with the TableSearch
 * @param {String} selectedConcurrent - space separated name of searches to execute
 */


/**
 * @param {Object} obj
 * @param {String} obj.raKey
 * @param {String} obj.decKey
 * @param {String} obj.hipsUrl
 * @param {WorldPt} obj.centerPt
 * @param {number} obj.hipsFOVInDeg
 * @param {CoordinateSys} obj.coordinateSys
 * @param {Array.<{mocUrl:String, mocColor:String, title:String}>} obj.mocList
 * @param {boolean} obj.nullAllowed
 * @param {number} obj.minValue
 * @param {number} obj.maxValue
 * @param {String} obj.targetPanelExampleRow1
 * @param {String} obj.targetPanelExampleRow2
 * @param {String} sRegion
 * @return {FieldDef}
 */


/**
 *
 * @param {Object} obj
 * @param {String} obj.key
 * @param {String} obj.targetKey
 * @param {String} [obj.sizeKey]
 * @param obj.minValue
 * @param obj.maxValue
 * @param {String} obj.desc
 * @param {String} obj.tooltip
 * @param obj.initValue
 * @param obj.nullAllowed
 * @param obj.centerPt
 * @param obj.hipsFOVInDeg
 * @param obj.coordinateSys
 * @param {String} [obj.sRegion]  an obsCore s_region type string
 * @param obj.hipsUrl
 * @param {Array.<{mocUrl:String, mocColor:String, title:String}>} obj.mocList
 * @param {String} [obj.targetPanelExampleRow1]
 * @param {String} [obj.targetPanelExampleRow2]
 * @returns {FieldDef}
 */


/**
 *
 * @param url - location of file can reference a file on the server
 * @param idx - table index in file
 * @param initArgs - object of initial arguments, used by web api
 * @param {String} dlAction = the action command for the dropdown
 * @returns {Promise<void>}
 */


/**
 * recenter hips if no target entered, change hips if new one is specified
 *
 * @param {String} currentTblId
 * @param {QueryAnalysis} qAna - the description of all the searches to do for this table
 * @param {String} groupKey
 * @param {Array.<FieldDef>} fieldDefAry
 */


/**
 * map the primarySearchDef (a SearchDefinition) array in QueryAnalysis to an array of FieldDef arrays.
 * Usually there is only one primarySearchDef
 *
 * @param {QueryAnalysis} qAna - the description of all the searches to do for this table
 * @param {Object} initArgs
 * @param {number} defaultMaxMOCFetchDepth
 * @return {Array.<Array.<FieldDef>>}
 */


/**
 *
 * @param {Object} p
 * @param {ServiceDescriptorDef} p.serviceDef
 * @param {String} [p.sRegion]
 * @param {SearchAreaInfo} [p.searchAreaInfo]
 * @param {boolean} [p.hidePredefinedStringFields]
 * @param {String} [p.hipsUrl]
 * @param {Number} [p.fovSize]
 * @returns {Array.<FieldDef>}
 */


/**
 *
 * @param {Object} p
 * @param {ServiceDescriptorInputParam} p.serDefParam
 * @param {String} [p.sRegion]
 * @param {SearchAreaInfo} [p.searchAreaInfo]
 * @param {boolean} [p.hidePredefinedStringFields]
 * @param {String} [p.hipsUrl]
 * @param {Number} [p.fovSize]
 * @return {FieldDef}
 */


/**
 *
 * @param {Object} cisxUI
 * @param {number} defaultMaxMOCFetchDepth
 * @return {SearchAreaInfo}
 */


/**
 *
 * @param {Array.<FieldDef>} fdAry
 * @param args - object of init values
 * @return {Array.<FieldDef>} array with defaults
 */


//check for and return a datalink service descriptor url and input params, if one is found


// Function to search for a node in the tree


/**
 * Add quotes around a table or column name if it is not already quoted and if non-standard names.
 * @param {string} name a table or column name
 * @param {boolean} [isTable] - if the the name is a table name otherwise it is a colunm name
 * @return {string}
 */


/*
 * Takes a ranges list and returns a list of sia constraints (query params)
 */


/**
* comments updated 24aug92.
* j.bennett
* jcnvp2 version of jcnvpa that can handle julian prec., etc. -
*      has tobsin arg. that jcnvpa does not have.
*      calls jcnvc2 instead of jcnvcd (still needs subs in jcnvcd though)
*
*
*       ALL FLOATING POINT ARGS ARE DOUBLE PRECISION
*
* @param {number} jsysin is coord. system of input:
*          1 = equ(Bess); 2 = gal; 3 = ecl(Bess); 4 = sgl.
*          0 = equ(Jul); 11 = equ(Jul)=same as 0; 13 = ecl(Jul)
*
* @param {number} epokpa is equinox of pain (ignored if jsysin > 2 or 4)- if 0.0d0, then
*         routine sets epokpa = to equinox of input position.
* @param {number} distin = semi=major axis of error ellipse (really used only as flag-
*        if distin <= 0.d0, then position angle comp. not done).
* @param {number} pain = input position angle (0 to 180.0d0 deg.)
* @param {number} epoki is equinox of xlonin,xlatin (ignored if jsysin = 2 or 4; If 0.0d0
*         1950.0d0 is assumed if jsysin 1 or 3;  2000.0d0 if jsysin
*         0, 11, or 13)
* @param {number} xlonin,xlatin  coordinates of input position
 * @param {number} xlatin
* @param {number} tobsin is observation epoch (needed for B1950 <==> J2000 system conversions)
*          if tobsin = 0.0d0, then 1950.0d0 is used.
* @param {number} jsysou is coord system of output (see jsysin for values).
* @param {number} epoko is equinox of output. Same default rules as for epoki, but is function
*       of jsysou.
* @param {number} paou is output position angle in jsysou, equinox=epoko if
*         distin > 0.0d0  and ierr = 0 ( garbage otherwise).
* @param {number} xlonou,xlatou is output position in jsysou, equinox=epoko.
 * @param {number} xlatou
* @param {number} ierr = 0 for normal return. -1 if paou could not be computed when
*   distin > 0.d0
*
* NOTE:
* paou computed only if distin > 0.0d0 deg. (however 0.1 deg. is used
*      for distance in recomputation of pa.
* This routine will enforce the assumption that equinox = 1950. for
    *    galactic and supergalactic coordinate systems.
* This routine assumes input pos angle & input position are in the same
*    coordinate system (however, if equ, not necessarily the same equinox).
*
*
*  NOTE:  result in position angle not same when going in two steps
*         from J2000 to B1950 to galactic as when going in one step
*         from J2000 to galactic because an intermediate position angle
*         is computed for B1950 and used to create point to convert
*         to galactic in two-step process.
*
* calls jbposa,jbelpt,jcnvc2
*/


/**
 * galeqd,equgad,sglgal,galsgl subroutines moved from jcnvcd.f file to galeqd.f
 *   on 14sep92 - no changes to code, itself, made (code same as 17jan91)
 *
 * galeqd (modifcation of galequ) requires double prec. args (22oct90)
 *
 ****  entry equcor(xl,xb,rad,decd)   obsolete entry pt equcor.
 * 22mar85 for hepvax (changed darsin to dasin;removed entry equcor)
 * 17mar82 updated so has more sensible name- galequ, but still
 *   retains alias for equcor.
 * 02oct80  jdb   29jan81 to input dtor,rtod to more places. 22apr81
 * subroutine to compute earth equatorial coords from galactic coords
 * inputs:
 * @param xl l in degrees
 * @param xb b in degrees.
 * @return {{ra: number, dec: number}}
 * b = galactic latitude (-90. to + 90. deg);l=galactic longitude(0-360)
 * outputs:
 *  x = cos(b)*cos(l)
 *  y = sin(l)*cos(b)
 *  z = sin(b)
 *  gal <==> equ equations from tom soifer.  see also:
 *   Classical Mechanics by Herbert Goldstein (Addison-Wesley Publ.Co.,
 *     c.1950, 7th printing 1965) Section 4-4 on Eulerian Angles (p.107-109)
 *
 * assumes gal north pole at 12h 49.0m, +27d24' (192.25d,+27.4d)
 *         gal (0, 0) at     17h 42.4m, -28d55' (265.36d,-28.91d)
 *   also: delta=lat=0 at gal (33d,0d) ; equ (282.25d,0d).
 *
 */


/**
 * equgad (modification of equgal) requires double prec. args (22oct90)
 *
 * 22mar85 for hepvax (darsin changed to dasin;entry galcor removed)
 **    entry galcor(rad,decd,xl,xb)
 * 17mar82 updated for more sensible name- equgal, while retaining
 *     alias for old name of galcor.
 * 02oct80 jdb:subroutine to compute galactic coords from earth
 *  equatorial coords.29jan81 for more places in dtor,rtod.22apr81
 *  gal <==>equ equations from tom soifer.  see also:
 *   Classical Mechanics by Herbert Goldstein (Addison-Wesley Publ.Co.,
 *     c.1950, 7th printing 1965) Section 4-4 on Eulerian Angles (p.107-109)
 * assumes gal north pole at 12h 49.0m, +27d24' (192.25d,+27.4d)
 *         gal (0, 0) at     17h 42.4m, -28d55' (265.36d,-28.91d)
 *   also: delta=lat=0 at gal (33d,0d) ; equ (282.25d,0d).
 *
 * inputs:
 * @param rad ra in degrees,
 * @param decd is dec in degrees.
 * @return {{ra: number, dec: number}}
 * b = galactic latitude (-90. to + 90. deg);l=galactic longitude(0-360)
 *
 *  x = cos(alpha)*cos(delta)
 *  y = sin(alpha)*cos(delta)
 *  z = sin(delta)
 *  eq1 = sin(b) = -.8676*x - .1884*y + .4602*z
 *  eq2 = cos(b)*cos(l) = -.0669*x - .8728*y - .4835*z
 *  eq3 = cos(b)*sin(l) = +.4927*x - .4503*y + .7446*z
 *    b = arsin(sin(b))
 *  cos(b) = sqrt(1.-sin(b)*sin(b))
 *  cos(l) = eq2/cos(b)
 *  sin(l) = eq3/cos(b)
 *  l = atan2(sin(l)/cos(l): if(l.lt.0) l = l+2*pi if radians.
 *
 */


/**
 *
 * galsgl (modification of equgad) to compute supergalactic coordinates
 *  from galactic coordinates.  j.bennett  30oct-05nov90
 *
 * inputs:
 * @param rad =  gal lon (l) in degrees. double precision.
 * @param decd = gal lat (b) in degrees. double precision.
 * @return {{ra: number, dec: number}}
 * returned:
 * xb = supergalactic latitude  (SGB)  (-90. to + 90. deg). double precision.
 * xl = supergalactic longitude (SGL)  (0-360. deg). double precision.
 *
 *  Computed values of rotation used for the Eulerian angles:
 *   phi = 137.37 deg.;  theta = 83.68 deg.;  psi = 0. deg.
 *    Based on gal l,b = 137.37, 0 deg. at sg SGL,SGB = 0., 0. and
 *         SG North Pole (0,+90) at gal l,b = 47.37, +6.32 deg.
 *
 * References:
 * de Vaucouleurs,G., A. de Vaucouleurs, and G.H.Corwin,
 *  Second Reference Catalog of Bright Galaxies, (1976), p.8
 *
 * Tully,B., Nearby Galaxies Catalog, (1988) p. 1,4-5
 *
 *    Note: de Vaucouleurs gives gal l,b 137.29, 0 for SGL,SGB= 0,0;
 *          this is not 90 degrees from Galactic North Pole.- used
 *          Tully's value of 137.37, 0 deg.
 *
 *  gal <==> equ equations from tom soifer.  see also:
 *   Classical Mechanics by Herbert Goldstein (Addison-Wesley Publ.Co.,
 *     c.1950, 7th printing 1965) Section 4-4 on Eulerian Angles
 *     (p.107-109)
 *    note: such equations also appropriate for gal <==> sgl .
 *          See code below for def. of arrays a,b,c.
 *  x = cos(lon)*cos(lat)
 *  y = sin(lon)*cos(lat)
 *  z = sin(lat)
 *  eq1 = sin(sgb)          =   a(1)*x +  a(2)*y +  a(3)*z
 *  eq2 = cos(sgb)*cos(sgl) =   b(1)*x +  b(2)*y +  b(3)*z
 *  eq3 = cos(sgb)*sin(sgl) =   c(1)*x +  c(2)*y +  c(3)*z
 *  sgb = arsin(sin(sgb))
 *  cos(sgb) = sqrt(1.-sin(sgb)*sin(sgb))
 *  cos(sgl) = eq2/cos(sgb)
 *  sin(sgl) = eq3/cos(sgb)
 *  sgl = atan2(sin(sgl)/cos(sgl): if(sgl.lt.0) sgl = sgl+2*pi if radians.
 *
 */