Seismic and Segy Introduction

The Seismic and Segy widget classes are used to display a seismic section that the end-user can view and manipulate. The programmer has complete control over the display of the seismic section and the end-user, using a built-in panel, can change the resource values for the Seismic widget. Resources are defined for specifying the range of traces to be displayed, the type of trace display to be used, trace normalizations, and annotation options. Traces can be accessed and annotated using primary and secondary keys. The widget also provides a zoom function that creates a scaled view of a selected area.

Widget Class

The Seismic widget class is the base class for displaying and editing seismic data. It defines the basic methods for accessing the header and trace information, for rasterizing the traces, etc. A Seismic widget can be created directly in instances where data is memory resident. The Seismic widget class also serves as a superclass for widget classes that specialize in handling seismic data that is stored in a specific file format. For example, the Segy class is specialized to handle seismic data stored in Seg-Y format in a file.

Data Specification

The data used by a Seismic widget is contained in memory resident data structures. The main data structure is an instance of type XintSeismicDataRec that can be created before or after the Seismic widget is created. You specify a pointer to this structure using the resource XmNdataRec. Structure XintSeismicDataRec contains a pointer to an array of traces that can be stored in floating point, integer or byte format. It also contains a pointer to an array containing header information that is used to access and annotate the traces, as well as information about the size and nature of the dataset.

The data for the Segy widget is specified as a filename of a dataset stored in the Segy format. All information regarding the size and type of this dataset is extracted directly from the file.


Trace Selection

Traces to display can be selected using a primary and an optional secondary key. The keys are defined by the application for each trace in the seismic section. You select a subset of the traces for display by setting the resources which specify the range and the increment for the primary and secondary keys. For instance, a stacked dataset can usually be indexed by using only the primary key (the trace number), and a CDP sorted dataset can be indexed by setting the primary key to be the CDP number and the secondary key to be the offset.

The Segy widget supports trace selection by a primary key which may be one of Trace, Trace Shot Sequence Number (TSSN), Shot Point Identifier (SPID), or Common Depth Point (CDP). A secondary key of Common Depth Point Trace (CDPTR) can be specified for pre-stack traces that have a primary key of CDP.


Trace Annotation

Traces can be annotated using the primary key values and the optional secondary key values. Several resources are defined for customizing the appearance and position of the annotation. The application can also supply alternate annotation through callback procedures.

Trace Processing

The Seismic widget class provides a built-in Automatic Gain Control (AGC) opera tion as well as a passband filter (an optimized mix-radix FFT routine for the Fourier transformation based on the Danielson-Lanczos formula) for processing the trace data before it is displayed. The application controls whether none, one or both of the built- in trace processing algorithms are to be applied to the data. Additional trace process ing functions can be defined by the application as callback procedures to augment or substitute for the built-in trace processing functions.

Gaps

The Seismic widget class provides a resource for specifying a gap between groups of displayed traces.

Seismic Data Display

A seismic section and its optional overlay may be displayed using a pixmap or an XImage. Since the Seismic widget is a subclass of the Image widget class, the application sets a resource to control which of these alternatives is used. Monochrome displays of the trace data are implemented using a bitmap for greater efficiency. An anti-aliasing algorithm is invoked in case of oversampling of the data (ie: the vertical scale is such that there are more samples than pixels to display). This algorithm ensures, for example,that a spike in the data will always be visible. The application can display additional graphics in the Seismic widget's window through callback procedures.

Creating a Seismic or Segy Widget

An application creates a Seismic or a Segy widget as a child of a container widget. During the creation process, the application uses resources to specify the seismic data structures, callback procedures for the trace processing operations and general plot attributes such as titles, axis annotation, and trace highlight color. If you need to scroll the Seismic or Segy widget, you can use a Motif ScrolledWindow widget or a INT Scroll widget as the parent widget.

Displaying a Seismic Section

When the Seismic widget is created and mapped it displays the seismic section, along with optional overlays that might have been specified for the Seismic widget via resources at widget creation time. If you first display an empty Seismic widget and then set the resources specifying the seismic section and/or optional overlay using an XtSetValues call, then the Seismic widget will display the data at that time.

Seismic Example

The following code example (see file seismic_1.c) illustrates how to create a Seismic widget displaying shot data separated by gaps. The data in this example is generated using a sine functions.

   #include <stdio.h>
   #include <math.h>
   #include <Xm/Xm.h>
   #include <Xm/RowColumn.h>
   #include <Xm/Form.h>
   #include <Xm/Separator.h>
   #include <Xm/PushBG.h>
   #include <Xm/ScrolledW.h>
   #include <Xint/Seismic.h>
   
   #define NSAMPLE         500  /* number of samples per trace */
   #define NTRACE          100  /* number of traces */
   
   #define k_num_controls          1
   #define k_exit                  0
   
   /* Declare subroutines */
   void BuildUI();
   
   /* Declare callback .. User control pushbuttons */
   static void ControlsProc(Widget, int, XtPointer);
   
   /* Declare global variables */
   Widget toplevel_widget;
   int i, j, n;
   Arg arg[20]; 
   
   /***
    *** Main
    ***/
   main(argc, argv)
   int argc;
   char *argv[];
   {
       XtAppContext app_context;
   
       n = 0;
       toplevel_widget = XtAppInitialize (&app_context, "Example", NULL, 0,
			                  &argc, argv, NULL,arg, n);
       BuildUI ();
   
       XtRealizeWidget(toplevel_widget);
       XtAppMainLoop(app_context);
   }
   
   /***
    *** BuildUI
    ***/
   void BuildUI ()
   {
       Widget main_form;            /* contains all other widgets */
       Widget scrolled_window;      /* contains the Seismic widget */
       Widget seismic_widget;       /* for displaying the trace data */
       Widget sep;                  /* separator widget ID */
       Widget controls_box;  
       Widget controls_pb[k_num_controls];
       static char *controls_pb_names[] =  {"Exit"};

       /* array for the keys - it must remain allocated as long as it is
          attached to the Seismic widget */
       static XintSeismicKeyRec key_info[NTRACE]; 
   
       /* array to contain the trace data - it is not copied by the widget 
          and must remain allocated as long as the Seismic widget exists */
       static float trace[NTRACE][NSAMPLE];
   
       /* array containing information about the seismic section - it is not
          copied by the widget and must remain allocated as long as the
          Seismic widget exists */
       static XintSeismicDataRec data_info;
   
       float scale = .25;
       float tpi = 25;
   
       /* Create form to contain all other widgets */
       n = 0;
       XtSetArg(arg[n], XmNwidth, 400); n++;
       XtSetArg(arg[n], XmNheight, 500); n++;
       main_form = XtCreateManagedWidget("main_form", xmFormWidgetClass, 
                                         toplevel_widget, arg, n);
   
       /* create separator */
       n = 0;
       XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNbottomOffset, 50); n++;
       sep = XtCreateManagedWidget("sep", xmSeparatorWidgetClass,
		                   main_form, arg, n);
   
       /* create a ScrolledWindow widget */
       n = 0;
       XtSetArg(arg[n], XmNtopAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNtopOffset, 0); n++;
       XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNleftOffset, 0); n++;
       XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNrightOffset, 0); n++;
       XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_WIDGET); n++;
       XtSetArg(arg[n], XmNbottomWidget, sep); n++;
       XtSetArg(arg[n], XmNbottomOffset, 20); n++;
       XtSetArg(arg[n], XmNscrollingPolicy, XmAUTOMATIC); n++;
       scrolled_window = XtCreateManagedWidget("scrolled_window",
		                               xmScrolledWindowWidgetClass, 
                                               main_form, arg, n);
   
       /* generate the synthetic traces */
       for (j=0; j<NTRACE; j++) {
            for (i=0; i<NSAMPLE; i++) trace[j][i] = sin((float) (i+j)/10.);
            key_info[j].skey = j%10 + 1; /* this is the channel number */
            key_info[j].pkey = j/10 + 1; /* this is the shot number   */

            /* pakey and sakey can contain any F.P. value you want.      */
            /* Here skey and pkey values are used to display the channel */
            /* number and the trace number as annotations.               */
            key_info[j].pakey = (float) key_info[j].pkey;
            key_info[j].sakey = (float) key_info[j].skey;
       }
   
       /* fill the structure that describes the dataset to the widget */
       data_info.data = (XtPointer) &trace[0][0];
       data_info.data_format = XintFLOAT_DATA_FORMAT;
       data_info.key_info = key_info;
       data_info.ntrace = NTRACE;
       data_info.starting_time = 0;
       data_info.sample_rate = 4.e-3;
       data_info.nsample = NSAMPLE;
       data_info.data_type = XintTIME_DATA;
   
       /* create the seismic widget */
       n = 0;
       XtSetArg(arg[n], XmNplotTitle, 
                        "Seismic example using\nSine function data"); n++;
       XtSetArg(arg[n], XmNdataRec, &data_info); n++;
   
       /* we set primaryKeyName and secondaryKeyName to non NULL values */
       /* to tell we want to use both keys for trace selection          */
       XtSetArg(arg[n], XmNprimaryKeyName, "Shot"); n++;
       XtSetArg(arg[n], XmNsecondaryKeyName, "Trace"); n++;
   
       /* we want to display trace 1 to 8 of every other shot */
       XtSetArg(arg[n], XmNprimaryKeyIncrement, 2); n++;
       XtSetArg(arg[n], XmNsecondaryKeyEnd, 8); n++;
   
       /* we want to see both primary and secondary annotations */
       XtSetArg(arg[n], XmNprimaryAnnotationName, "SHOT"); n++;
       XtSetArg(arg[n], XmNsecondaryAnnotationName, "CHAN"); n++;
   
       /* we want to annotate every 5th trace */
       XtSetArg(arg[n], XmNsecondaryAnnotationIncrement, 5); n++;
   
       /* we set gapKeyName to a non NULL value to indicate that */
       /* we want a gap between shots                            */
       XtSetArg(arg[n], XmNgapKeyName, "shot"); n++;
   
       /* set the scale factor and traces per inch (pass the address *.
       /* instead of the value for floating point resources).        */
       XtSetArg(arg[n], XmNscale, &scale); n++;
       XtSetArg(arg[n], XmNtracesPerInch, &tpi); n++;
       XtSetArg(arg[n], XmNautoMarginAdjust, XintADJUST_ALL); n++;
   
       seismic_widget = XtCreateManagedWidget("seismic_widget",
	                                      xintSeismicWidgetClass,  
                                              scrolled_window, arg, n);
   
       /* use default change panel provided in library */
       XtAddCallback(seismic_widget, XmNchangePanelCallback,
	             XintSeismicChangePanelCallback, NULL);
   
       /* create controls box */
       n = 0;
       XtSetArg(arg[n], XmNspacing, 15); n++;
       XtSetArg(arg[n], XmNorientation, XmHORIZONTAL); n++;
       XtSetArg(arg[n], XmNrightAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNrightOffset, 20); n++;
       XtSetArg(arg[n], XmNleftAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNleftOffset, 20); n++;
       XtSetArg(arg[n], XmNtopAttachment, XmATTACH_WIDGET); n++;
       XtSetArg(arg[n], XmNtopWidget, sep); n++;
       XtSetArg(arg[n], XmNtopWidget, sep); n++;
       XtSetArg(arg[n], XmNtopOffset, 10); n++;
       XtSetArg(arg[n], XmNbottomAttachment, XmATTACH_FORM); n++;
       XtSetArg(arg[n], XmNbottomOffset, 10); n++;
       controls_box = XtCreateManagedWidget("controls_box",
	                                    xmRowColumnWidgetClass, 
                                            main_form, arg, n);
   
       /* create control pushbuttons */
       n = 0;
       XtSetArg(arg[n], XmNpushButtonEnabled, True); n++;
       XtSetArg(arg[n], XmNmarginWidth, 4); n++;
       XtSetArg(arg[n], XmNmarginHeight, 4); n++;
       for (i=0; i < k_num_controls; i++) {
            j = n;
            XtSetArg(arg[j], XmNlabelString,
            XmStringCreateLtoR(controls_pb_names[i], XmSTRING_DEFAULT_CHARSET));
            j++;
            controls_pb[i] = XtCreateManagedWidget("control_buttons",
		                                   xmPushButtonGadgetClass, 
                                                   controls_box, arg, j);
            XtAddCallback(controls_pb[i], XmNactivateCallback, ControlsProc,
			  (XtPointer)i);
       }
   }
   
   /***
   *** ControlsProc
   ***/
   static void ControlsProc(Widget widget, int client_data, 
                            XtPointer call_data)
   {
       if (client_data == k_exit) exit (0);
   }

The output generated by example seismic_1.c is shown below:


Figure 15: Output produced by example seismic_1.c.


Segy Example

The following code section (see examples segy_2.c) illustrates how to create a Segy widget. The Segy widget is created inside a Scroll widget to provide fixed annotation scrolling.

   #include <stdio.h>
   #include <Xm/Xm.h>
   #include <Xm/RowColumn.h>
   #include <Xm/Form.h>
   #include <Xm/Separator.h>
   #include <Xm/PushBG.h>
   #include <Xint/Scroll.h>
   #include <Xint/Segy.h>
   
   /* Declare subroutines */
   void BuildUI();
   
   /* Declare global variables */
   Widget toplevel_widget;
   int i, j, n;            /* counters */
   Arg arg[20];            /* XtArgs   */
   
   /***
    *** Main
    ***/
   main(argc, argv)
   int argc;
   char *argv[];
   {
       XtAppContext app_context;
   
       n = 0;
       toplevel_widget = XtAppInitialize (&app_context, "Example", NULL, 0,
			                  &argc, argv, NULL,arg, n);
       BuildUI ();
   
       XtRealizeWidget(toplevel_widget);
       XtAppMainLoop(app_context);
   }
   
   /***
    *** BuildUI
    ***/
   void BuildUI ()
   {
       Widget int_scroll;            /* contains the Seismic widget */
       Widget segy_widget;           /* for displaying contents of SEG-Y file */
       float  traces_per_inch;
   
       /* create a Scroll widget */
       n = 0;
       XtSetArg(arg[n], XmNwidth, 500); n++;
       XtSetArg(arg[n], XmNheight, 500); n++;
       int_scroll = XtCreateManagedWidget("int_scroll",
			                  xintScrollWidgetClass, 
                                          toplevel_widget, arg, n);
   
       /* create the segy widget */
       traces_per_inch = 7.0;
       n = 0;
       XtSetArg(arg[n], XmNplotTitle, "Segy Example Using Stacked Data");;n++;
       XtSetArg(arg[n], XmNplotType, XintPOSITIVE_COLOR_FILL +
		                     XintNEGATIVE_COLOR_FILL + XintWIGGLE); n++;
       XtSetArg(arg[n], XmNcolorScale, XintCOLOR_SCALE_LEFT); n++;
       XtSetArg(arg[n], XmNcolormapFile, "seg.cmp"); n++;
       XtSetArg(arg[n], XmCColorScaleSize, 400); n++;
       XtSetArg(arg[n], XmNtracesPerInch, &traces_per_inch); n++;
       XtSetArg(arg[n], XmNsegyFilename, "segy1.dat"); n++;
       XtSetArg(arg[n], XmNautoMarginAdjust, XintADJUST_ALL); n++;
       
       segy_widget= XtCreateManagedWidget ("segy_widget", 
			                   xintSegyWidgetClass,
			                   int_scroll, arg, n);
       XmAddTabGroup(segy_widget);
       
       /* add callback procedure defined in the INT library for */
       /* displaying default change panel                       */
       XtAddCallback(segy_widget, XmNchangePanelCallback,
		     XintSegyChangePanelCallback, NULL);
   }

The output produced by example segy_2.c is illustrated below:


Figure 16: Output produced by example segy_2.c.


Muting the Trace Display

The display of any number of traces can be muted by the application via resources or functions. When a trace display is muted, the portion of a trace above a specified time value and/or below another specified time value is not displayed.

Controlling the Trace Display Status

The display of any number of traces can be controlled by the application via resources or functions. You can specify that a trace is not to be displayed at all, or that its display is inverted (+ to - and - to +).

Displaying an Overlay

You can use an additional set of seismic data structures to define an overlay data set to be displayed on top of the seismic section. The overlay data must be identical to the primary data set in data type, size and key indices. The overlay data structures can be created before or after the Seismic widget is created. You specify the overlay data to the widget via the resource, XmNoverlayData. A single set of the overlay data structures can be shared among several Seismic widgets.

The overlay option is also supported by the Segy widget class. You can specify the overlay data for a Segy dataset using resource XmNoverlaySegyFilename or resource XmNoverlayData. It that second case, you must make sure that the size and number of traces contained in the overlay is equal to that of the Segy filename.


Resource Editor

Both the Seismic and Segy widget have a built-in resource which can be activated using callback XmNchangePanelCallback. The default resource editor callback is XintSeismicChangePanelCallback for the Seismic widget and XintSegyChangePanelCallback for the Segy widget. Example seismic_1.c, listed above, uses the following instruction to register the resource editor panel for the seismic widget:

   XtAddCallback(seismic_widget, XmNchangePanelCallback,
                 XintSeismicChangePanelCallback, NULL);

You can also register your own resource editor callback.


Figure 17: Default Segy Resource Editor Panel.


Updating the Display

An application can update the display of a seismic section or overlay currently displayed by changing the scaling factor, the plot type, the range of data displayed or the underlying data in the seismic or overlay data structures. To change the attributes of a Segy or Seismic widget, you can use functions XtSetArg of XtSetValues. The following code sample illustrates how to change the plot type and interpolation mode for a segy widget.

   XtVaSetValues(segy, XmNplotType, XintWIGGLE,
              XmNinterpolationMode, XintQUADRATIC_INTERPOLATION,
              NULL);


Coordinate System

The Seismic and Segy widgets display a seismic section using a two dimensional coordinate system.

The data range to be displayed defines the horizontal axis. It is specified by the user through the primary key and secondary key resources. These allow the user to refer to the traces in familiar terms, such as Common Depth Point number and Trace number. The key values are converted internally by the Seismic widget to unique trace sequence numbers. INT objects use the trace sequence numbers to identify locations on the horizontal axis of the trace display. The two functions, XintSeismicTraceToKey and XintSeismicKeyToTrace, convert from a trace sequence number to key values and the reverse, respectively. Other functions convert a trace sequence number and time (XintSeismicTraceTimeToPoint) or key values and time (XintSeismicKeyTimeToPoint) to a location in the user coordinate system. The trace sequence number, key values and time for a location in the user coordinate system may be found with the XintSeismicPointToKeyTime function.

The vertical axis is defined by specifying as resource values the number of inches per second (or inches per kilofeet or kilometers) and the starting and ending time (or depth) of the trace samples to be displayed. These values can be changed as needed to redefine the time (or depth) range of the samples currently displayed using Seismic resources XmNstartingTime and XmNendingTime.

Functions are provided in the CompBase and the Seismic widget class for converting a location in the user coordinate system to and from the device coordinate system.


Trace Positioning

Traces are normally spaced on a constant increment depending on resource XmNtracesPerInch. It is also possible to position the traces at a non constant interval using resource XmNtracePositionArray. This resource specifies the position at which each trace is drawn. If you use this resource, you must also define the horizontal coordinate system (using Grid resources XmNhorizontalStart and XmNhorizontalEnd), which is used to specify the trace positions, and the size of the plot (resource XmNimageWidth). The following code segment (from example seislog_2.c) illustrates how to use resource XmNtracePositionArray to create two gaps used to display log data. Variable pixels_per_trace contains the trace spacing in pixels and variable log_width specifies the width of the gap for the log in pixels.
   ...
   start = 0;
   end = ntraces * pixels_per_trace + 1 + 2 * log_width;
   width = end - start + 1;

   /* create segy widget */
   n = 0;
   XtSetArg(arg[n], XmNplotTitle, "Stack Line\n 128-B"); n++;
   XtSetArg(arg[n], XmNprimaryKeyEnd, ntraces); n++;
   XtSetArg(arg[n], XmNsegyFilename, "goliad.stk"); n++;
   XtSetArg(arg[n], XmNautoMarginAdjust, XintADJUST_ALL); n++;
   XtSetArg(arg[n], XmNtracePositionArray, trace_positions); n++;
   XtSetArg(arg[n], XmNhorizontalStart, &start); n++;
   XtSetArg(arg[n], XmNhorizontalEnd, &end); n++;
   XtSetArg(arg[n], XmNimageWidth, width); n++;
   XtSetArg(arg[n], XmNplotType, XintCOLOR_FILL); n++;
   XtSetArg(arg[n], XmNcolormapFile, "seg.cmp"); n++;
   XtSetArg(arg[n], XmNscale, &scale); n++;
   segy = XtCreateManagedWidget("segy", xintSegyWidgetClass,
                                segy_scroll, arg, n);
   ...


Colors

The colormap used by a Seismic widget for displaying color plots is specified using a data structure called XintColorRec and Image class resource XmNcolorRecord. You can either allocate the colors yourself and build a color record using supplied function XintImageCreateColorRecord or let the Seismic widget class allocate the colors for you. The Seismic widget class can create an XintColorRec structure by reading a colormap file (specified with resource XmNcolormapFile) or by generating a gray scale colormap. You can share a XintColorRec structure among several Seismic widgets or other widget classes based on the Image class, such as PlotXY or Contour.

The following code sample illustrates how to create two Segy widgets which share the same colormap.

   Widget segy1, segy2;
   XintColorRec *color_record;
   ...
   /* create first segy widget */
   segy1 = XtVaCreateManagedWidget("segy1", xintSegyWidgetClass, parent,
                                   XmNcolormapFile, "seg.cmp",
                                   XmNplotType, XintCOLOR_FILL,
                                   XmNsegyFilename, "segy1.dat", NULL);

   /* extract color record */
   XtVaGetValues(segy1, XmMcolorRecord, &color_record, NULL);

   /* create second segy widget */
   segy2 = XtVaCreateManagedWidget("segy2", xintSegyWidgetClass, parent,
                                   XmNcolorRecord, color_record,
                                   XmNplotType, XintCOLOR_FILL,
                                   XmNsegyFilename, "segy2.dat", NULL);
   ...

In this example, the colormap is allocated directly by the first Segy widget. You could also create the color record directly, using function XintReadColormap (see EditColormap widget) and function XintImageCreateColorRecord as illustrated below:

   Pixel *pixels;
   int ncolors;
   int err_code;
   ...
   pixels = XintReadColormap(parent, "seg.cmp", &ncolors, &err_code);
   if (pixels) {
       color_record = XintImageCreateColorRecord(pixels, ncolors);

       /* create first segy widget */
       segy1 = XtVaCreateManagedWidget("segy1", xintSegyWidgetClass, 
                                       parent,
                                       XmNcolorRecord, color_record,
                                       XmNplotType, XintCOLOR_FILL,
                                       XmNsegyFilename, "segy1.dat", NULL);
       ...
   } else {
       /* error allocating colors */
       ...
   }


Color Scale

An optional color scale can be used to indicate the colors corresponding to amplitudes in the seismic section or overlay. Resources defined by the Image widget class are used to specify the color scale location and annotation.

Zooming the Seismic Section Display

The end-user or the application can specify an area to be enlarged via two different zoom operations. One method scales the seismic section and displays it within the same Seismic or Segy widget. The other method scales the seismic section and displays it inside a newly created Seismic or Segy widget. A zoomed view of the seismic section created by either method can itself be enlarged by another zoom operation.

EditObject callback XmNareaSelectionCallback can be used to let the end-user specify the rectangular area used for zooming. Grid function XintGridZoom can be used to zoom both a Seismic or Segy widget as described above.


Producing a Movie or Slideshow

The Seismic widget class can be used to display images, allowing the application to build movies, to toggle between two seismic images, etc. Set Image resource XmNmovieMode to True and pass your own pixmap using resource XmNpixmap to temporarily replace the current seismic display with your own image. It is up to the application to manage the list of pixmaps that are used for the animation.

The Seismic and Segy widgets can also be used to generate pixmaps or images that can be used by the Movie widget to build animations. See function XintSeismicGetInfoForMovie for extracting information used to build a Movie frame from a seismic display.


Producing Hardcopy

A scaled image of a seismic section displayed by a Seismic widget can be output to a color or monochrome Postscript file using a supplied function. CGM+ output capability is available as a separate option. Additionally, the application can include its own output in the PostScript or CGM+ file. See the description of the CompBase widget class for additional information on hardcopy output.