How can I create an image of satellite pixel using 4 latitude/longitude corner points instead of a 1 center lat/long coordinate

Hello,

I want to plot native swath satellite data without regridding it to a linear lat/long grid. Each ground pixel comes with its own set of 4 lat/long corner points describing its surface footprint. The grid that is created by these footprints has no gaps, but it is non linear and the pixel have different sizes. I would like to plot this as an image and fill each 4 sided polygon created by the corner points with color according to a color code based on the value for this pixel.

Any help appreciated, Thanks 

If the satellite data is just non-linearly gridded, you can supply those coordinates to an Igor image plot using auxillary X and Y waves.

For more info, enter the following on Igor's command line:

DisplayHelpTopic "Image X and Y Coordinates - Unevenly Spaced"

 

Hello,

Thank you for this reply, which made me realize I was not sufficiently clear in my description. The pixel are are not rectangles, but something more like not fully linear parallelograms that change size across the image (field of view). In short, I would need to be able to supply individual x and y scalings for each row and column of the image matrix. I am attaching an image to illustrate what I would like to plot. The example image I have available is from the center of the satellite's field of view, where the pixel almost all have the same size, but across the whole image each image has a different size that is only determined by its corner latitude/longitude points. Perhaps wanting to plot it as as image is not the right approach?

Thanks and Best, Barbara 

You should probably use the Drawing Tools to create this, then. It might not render very quickly, though, and the recreation macro would be huge. Still, it should work. If the drawing tools are new to you, start with this help topic:

DisplayHelpTopic "Drawing"

The useful thing about drawing tools is that you can write code to create the drawings, and you can use the graph coordinate system to place lines, rectangles and polygons.

You can set the color of the poly before you draw it, too.

I imagine code that loops through your loaded data and executes SetDrawEnv fillRGB commands to set the color and then DrawPoly commands.

Like this:

Function DemoPolyDrawing()

    String win="DemoPolyDrawingGraph"
    DoWindow/K $win
    Display/N=$win /W=(35,45,430,253)
    NewFreeAxis/O/L freeLeft
    NewFreeAxis/O/B freeBottom
    ModifyGraph freePos(freeLeft)=0
    ModifyGraph freePos(freeBottom)=0

    // axis range
    Variable xmin=10, xmax=60
    Variable ymin=20, ymax=35

    SetAxis freeBottom xmin,xmax+10
    SetAxis freeLeft ymin,ymax

    SetDrawEnv xcoord=freeBottom, ycoord=freeLeft, fillpat=1, save  // 100% fill
    ColorTab2Wave Rainbow // creates M_Colors
    WAVE M_Colors           // needed to refer to M_Colors
    Variable i, nColors = DimSize(M_Colors,0)
    // generate a bunch of closed polys with 4 corners (5 points), and sequential colors from Rainbow
    Variable dx= 5, dy=1, xskew=1, yskew=0.2
    Variable xrange = (xmax-xmin)
    Variable yrange = (ymax-xmin) - dy
    for(i=0; i<nColors; i+=1)
        Variable xOffset = mod(i*dx,xrange)
        Variable xRow = floor(i*dx/xrange)
        Variable x0 = xmin + xOffset + xRow * xSkew
        Variable x1 = x0 + dx
        Variable x2 = x1 + xSkew
        Variable x3 = x0 + xSkew
       
        Variable y0 = ymin + xRow*(dy+ySkew)
        Variable y1 = y0 + ySkew
        Variable y2 = y1 + dy
        Variable y3 = y0 + dy
       
        Variable red= M_Colors[i][0]
        Variable green= M_Colors[i][1]
        Variable blue= M_Colors[i][2]
        SetDrawEnv fillfgc=(red,green,blue)
        DrawPoly x0, y0, 1, 1, {x0,y0, x1,y1, x2,y2, x3,y3, x0,y0}
    endfor
End

 

DemoPolyDrawingGraph.png (46.84 KB)

Thank you very much, this is extremely helpful. I will check it out and if the rendering is too time consuming I will at least have it available for select cases.

Much appreciated, Cheers and Best,

Barbara

I think that there is another approach that may or may not have coding or rendering advantages. It is a little complicated, but not much more than programming the drawing tools. The suggestion is to use Gizmo, and construct a Group using quad objects for the irregular pixels. All quads would have the same fixed z-coordinate, each with its own four x,y vertex values. To get started

DisplayHelpTopic "Group Objects"

 To give a flavor of a coding example, here is how I altered the color of one quad, in a two-quad group, setting it to green:

    ModifyGizmo currentGroupObject="Gizmo0:group0"
    ModifyGizmo modifyObject=quad0, objectType=quad, property={colorValue,0, 0,1,0,1}
    ModifyGizmo currentGroupObject="::"

You could use 2 Nx4 waves to hold all your vertex 'x' and 'y' values for each pixel ('z' is an arbitrary constant for the plane), and write a loop to construct each set of quad coordinates in the group. Coloring each quad would proceed as shown above, using an Nx4 wave of your color values (R,G,B,alpha) for each pixel (quad). Here is the recreation macro for my test Gizmo with two quads; converting to a loop structure over pixels should not be too difficult.

Window Gizmo0() : GizmoPlot
    PauseUpdate; Silent 1       // building window...
    // Building Gizmo 8 window...
    NewGizmo/W=(26.25,50,412.5,395)
    ModifyGizmo startRecMacro=700
    ModifyGizmo scalingOption=63
    AppendToGizmo Axes=boxAxes,name=axes0
    ModifyGizmo ModifyObject=axes0,objectType=Axes,property={-1,axisScalingMode,1}
    ModifyGizmo ModifyObject=axes0,objectType=Axes,property={-1,axisColor,0,0,0,1}
    ModifyGizmo ModifyObject=axes0,objectType=Axes,property={0,ticks,3}
    ModifyGizmo ModifyObject=axes0,objectType=Axes,property={1,ticks,3}
    ModifyGizmo ModifyObject=axes0,objectType=Axes,property={2,ticks,3}
    ModifyGizmo modifyObject=axes0,objectType=Axes,property={-1,Clipped,0}
    AppendToGizmo group,name=group0
   
    // ************************* Group Object Start *******************
    ModifyGizmo currentGroupObject="group0"
    AppendToGizmo quad={-0.25,-0.25,0,0,-0.25,0,0,0,0,-0.25,0,0},name=quad0
    ModifyGizmo ModifyObject=quad0,objectType=quad,property={ colorType,1}
    ModifyGizmo ModifyObject=quad0,objectType=quad,property={ colorValue,0,0,1,0,1}
    AppendToGizmo quad={0,0,0,0.25,0,0,0.25,0.25,0,0,0.25,0},name=quad1
    ModifyGizmo ModifyObject=quad1,objectType=quad,property={ colorType,1}
    ModifyGizmo ModifyObject=quad1,objectType=quad,property={ colorValue,0,1.5259e-05,0.244434,1,1}
    ModifyGizmo setDisplayList=0, object=quad0
    ModifyGizmo setDisplayList=1, object=quad1
    ModifyGizmo currentGroupObject="::"

    // ************************* Group Object End *******************
   
    AppendToGizmo freeAxesCue={0,0,0,1},name=freeAxesCue0
    ModifyGizmo setDisplayList=0, object=axes0
    ModifyGizmo setDisplayList=1, object=group0
    ModifyGizmo setDisplayList=2, object=freeAxesCue0
    ModifyGizmo autoscaling=1
    ModifyGizmo currentGroupObject=""
    ModifyGizmo showInfo
    ModifyGizmo infoWindow={610,68,1226,366}
    ModifyGizmo endRecMacro
    ModifyGizmo idleEventQuaternion={8.1789e-07,5.63137e-07,6.43585e-07,1}
EndMacro

(Edit: Macro transcription error corrected)

Here is a Gizmo comparison to Jim's previous graph. In practice the user supplies the wNx and wNy vertex values and color scale values, which I have concocted. Prior to executing the function below I opened a Gizmo window with initial box axes, translate, and scale operations. to simplify the example, I also opted not to use a group of quads

function QuadLoop() //  constructs flat (z=0) surface plot of area-filling parallelograms
    string Quadstring     // varying quad label
    WAVE wNx, wNy, wcolor // (35,4) x and y vertex values; (35,3) colorscale values based on Rainbow, indexed by pixel number
    variable i
    for(i=0;i<35;i+=1) 
        Quadstring= "quad"+num2str(i)
        AppendToGizmo quad={wNx[i][0],wNy[i][0],0, wNx[i][1],wNy[i][1],0, wNx[i][2],wNy[i][2],0, wNx[i][3],wNy[i][3],0},name=$QuadString
        ModifyGizmo ModifyObject=$QuadString,objectType=quad,property={ colorType,1}
        ModifyGizmo ModifyObject=$QuadString,objectType=quad,property={ colorValue,0, wcolor[i][0],wcolor[i][1],wcolor[i][2], 1}
        ModifyGizmo setDisplayList=i+3, object=$QuadString
    endfor
end

The attached figure shows a vertical (home) view of the gap-less pixels' surface in the z=0 plane

parallelogram quads Gizmo display (79.06 KB)

After helpful discussions with AG, my current opinion is that a Gizmo Surface plot using sequential quads for the source wave is the easiest way to go.

DisplayHelpTopic "Surface Object Data Formats"

All you have to do is put your data into the specified source wave format. Here is a code snippet for one kind of conversion:

Function ShowQuad(wX, wY, wZ) //    creates source wave for sequential Quad surface from vertex waves
    wave wX, wY, wZ           //    vertex coordinate values [numquads, 4 vertices];
                              //    one coordinate has four identical vertex values, representing measured datum
                              //    the other two coordinates have different vertex values for lat/long corners
   
    variable npts = dimsize(wX,0)  //   number of quads
    make/O/N=((npts),4,3) wSeqQuad // (quads, vertices, coordinate values)
    wSeqQuad[][][0]=wX[p][q]       // Gizmo surface and axes and are added and modified from GUIs
    wSeqQuad[][][1]=wY[p][q]
    wSeqQuad[][][2]=wZ[p][q]   
End

I am attaching a picture of a Gizmo projected view using simulated vertices (the color wave shows the data values along the projection axes, taken from one coordinate of vertex data). There are only two Gizmo objects involved, axes and surface plot.

SequentialQuadSurface (220.29 KB)