00001
00007 #include <stdio.h>
00008 #include <stdlib.h>
00009 #include <ctype.h>
00010 #include <string.h>
00011 #include <math.h>
00012 #include <vector>
00013 using std::vector;
00014
00015 #include "ipc.h"
00016 #include "cmdparam.h"
00017
00018 #ifndef NO_INPUTS
00019 #include "inputs.h"
00020 #endif
00021
00022 #include "analyze.h"
00023 #include "globals.h"
00024 #include "lissom.h"
00025
00026 #include "ppm_draw.h"
00027
00028
00029
00030
00031
00032
00033 00034 00035 00036
00037
00039 typedef unsigned char RGB_value;
00040
00042 #define HIGHEST_COLOR_LEVEL 255
00043
00045 #define BadPixel ((char)(1<<5))
00046
00047
00048 typedef struct
00049 {
00050 RGB_value red;
00051 RGB_value green;
00052 RGB_value blue;
00053 char flags;
00054 } XColor;
00055
00057 #define NOHUE -1.0
00058
00059
00060 00061 00062 00063 00064
00065
00066 #define PPM_RYW 0
00067 #define PPM_GRAYSCALE 1
00068 #define PPM_ORIENTATION 2
00069 #define PPM_OCULARDOMINANCE 3
00070 #define PPM_SINGLEHUE 4
00071 #define PPM_NONE 5
00072 #define PPM_SELECTIVITY 6
00073 #define PPM_MAX_SUBPLOT 6
00074
00075
00076
00077 #define PPM_WTSCALE_FIXED 0
00078 #define PPM_WTSCALE_INHIB 1
00079 #define PPM_WTSCALE_COUNT 2
00080 #define PPM_WTSCALE_ACTIVE 3
00081 #define PPM_WTSCALE_PEAKRELATIVE 4
00082 #define PPM_WTSCALE_RELATIVE 5
00083 #define PPM_MAX_WTSCALE 5
00084
00085
00095 typedef int (*ppm_inside_test_ptr)
00096 (
00097 int i, int j,
00098 int int1, int int2, double float1, double float2,
00099 void *otherparams
00100 );
00101
00102
00103
00104
00105 #ifndef CROP
00106 #define CROP(lower,upper,x) (MAX((lower),MIN((upper),(x))));
00107 #endif
00108
00109
00110
00111
00112
00113
00114
00115
00116 double ppm_master_scale = 1.0;
00117 double ppm_retina_scale = Uninitialized;
00118 double ppm_cortex_scale = Uninitialized;
00119
00120 int ppm_border = MAX(2,(int)(NMAX*0.03));
00121
00122 double ppm_bg_R = Uninitialized;
00123 double ppm_bg_G = Uninitialized;
00124 double ppm_bg_B = Uninitialized;
00125
00126 double ppm_luminance_multiplier = 1;
00127 double ppm_lateral_multiplier = 700;
00128 double ppm_afferent_multiplier = 100;
00129 double ppm_selectivity_multiplier = 1;
00130 double ppm_line_selectivity_multiplier = 50;
00131 double ppm_activity_luminance_offset = 0;
00132
00133 int ppm_weight_scale_type = PPM_WTSCALE_PEAKRELATIVE;
00134 int ppm_weight_scale_init_count = True;
00135 int ppm_weight_scale_max_count = True;
00136
00137 int ppm_neuron_skip_aff = 1;
00138
00139 int ppm_paper_based_colors = False;
00140 int ppm_paper_based_retina = Uninitialized;
00141 int ppm_outline_weights = True;
00142 int ppm_outline_retina = True;
00143 int ppm_always_mark_neuron = False;
00144 int ppm_retina_edge_buffer_suppress=False;
00145
00146 int ppm_activity_subplot = PPM_RYW;
00147 int ppm_retina_subplot = PPM_RYW;
00148 int ppm_lateral_subplot = PPM_RYW;
00149 int ppm_afferent_subplot = PPM_RYW;
00150 int ppm_orientation_subplot = PPM_NONE;
00151 int ppm_ocular_dominance_subplot = PPM_RYW;
00152 int ppm_line_orientation_subplot = PPM_SELECTIVITY;
00153
00154 double ppm_subplot_hue = NOHUE;
00155
00156 int ppm_line_plots = False;
00157 int ppm_shaded_plots = True;
00158 int ppm_always_draw_point = True;
00159 int ppm_neuron_skip_line = 1;
00160 int ppm_neuron_ioffset_line = 0;
00161 int ppm_neuron_joffset_line = 0;
00162 int ppm_interior_border = 1;
00163 int ppm_interior_outline = False;
00164
00165 double ppm_line_R = Uninitialized;
00166 double ppm_line_G = Uninitialized;
00167 double ppm_line_B = Uninitialized;
00168
00169 int ppm_start_i = Uninitialized;
00170 int ppm_start_j = Uninitialized;
00171 int ppm_end_i = Uninitialized;
00172 int ppm_end_j = Uninitialized;
00173
00174 int ppm_start_x = Uninitialized;
00175 int ppm_start_y = Uninitialized;
00176 int ppm_end_x = Uninitialized;
00177 int ppm_end_y = Uninitialized;
00178
00179 int ppm_ui = Uninitialized;
00180 int ppm_uj = Uninitialized;
00181
00182 double ppm_weight_threshold = DEATH_FLAG;
00183 int ppm_outline_width = 1;
00184 double ppm_reference_angle = 0;
00185
00186 double ppm_value_range = 0.6;
00187 double ppm_value_offset = 0.1;
00188
00189 int ppm_minimal_outline = False;
00190
00191 double ppm_histo_percentage_range = 25;
00192 double ppm_histo_scale_factor = 0.25;
00193 int ppm_histograms = True;
00194
00195 char ppm_image_viewer[MAXFILENAMELENGTH]="xv -expand 4 -raw";
00196 char ppm_remote_viewer[MAXFILENAMELENGTH]="anytoascii";
00197 int& ppm_spawn_viewer=spawn_viewer;
00198 int ppm_spawn_independent_viewers=True;
00199
00200 int ppm_color_keys=Uninitialized;
00201 int ppm_color_key_num=13;
00202
00203 int ppm_combine_alternate_eyes = False;
00204
00205
00206
00207
00208
00209 XColor colors[HIGHEST_COLOR_LEVEL+1];
00210 XColor image[IMG_SIZE_X][IMG_SIZE_Y];
00212 XColor ppm_background_color;
00213 XColor ppm_foreground_color;
00214
00215 int ncolors=252;
00216 int ppm_height = 0;
00217
00218
00219 const XColor Black = {0,0,0,0};
00220 const XColor White = {HIGHEST_COLOR_LEVEL,HIGHEST_COLOR_LEVEL,HIGHEST_COLOR_LEVEL,0};
00221 const XColor Blue = {0,0,HIGHEST_COLOR_LEVEL,0};
00222
00223
00224
00225
00226
00227
00228
00229
00230 void BhamXDrawLine_PointsAlongX(int xA, int yA, int xB, int yB, int direction, XColor color, int thickness);
00231 void BhamXDrawLine_PointsAlongY(int xA, int yA, int xB, int yB, int direction, XColor color, int thickness);
00232 int canExtendWidthTo(int width);
00233 void compute_weight_scale( int ui, int uj, int max_coord, int circular_wts,
00234 int radius, int ar_width,
00235 void* weights, int weights_are_lat,
00236 double* factor, double* offset );
00237 void create_colormap_RGB( XColor colormap[HIGHEST_COLOR_LEVEL+1], int numcolors );
00238 int draw_box_outline( XColor color, int xl, int xh, int yl, int yh, int width );
00239 int draw_box_outline_on_cortex( double centeri, double centerj, double radius, int left_offset);
00240 int draw_box_outline_on_retina( double centeri, double centerj, double radius, int left_offset);
00241 void draw_histogram_bin( double value, int j, int reset_values, int draw_zero, int left_offset);
00242 void draw_horizontal_line( XColor color, int l_i, int h_i, int j );
00243 int draw_outline_on_cortex( int ui, int uj, int radius, int left_offset, ppm_inside_test_ptr testfn);
00244 int draw_outline_on_retina( int ui, int uj, int radius, int left_offset, ppm_inside_test_ptr testfn);
00245 void draw_rectangle ( XColor color, int upper_left_x, int upper_left_y, int x_pixels, int y_pixels );
00246 void draw_retina_unit( XColor color, int x, int y, int reset_values, int left_offset);
00247 void draw_cortex_unit( XColor color, int i, int j, int reset_values, int left_offset);
00248 void draw_vertical_line( XColor color, int i, int l_j, int h_j );
00249 void hsv2rgb( double h, double s, double v, XColor *color );
00250 int inhWeightAbove( int i, int j, int ui, int uj, double radius, double threshold, void *dummyv );
00251 int isAlwaysInside( int i, int j, int int1, int int2, double float1, double float2, void *dummyv );
00252 int isInsideCircle( int i, int j, int centeri, int centerj, double radius, double dummyf, void *dummyv );
00253 void ppm_clear_image(int bg_R, int bg_G, int bg_B);
00254 void ppm_draw_line(int x_1, int y_1, int x_2, int y_2, XColor color, int thickness);
00255 void ppm_draw_line_at_angle(int cx, int cy, double angle, double length, double width, XColor color);
00256 int ppm_draw_od_pref(double od_pref_array[NMAX][NMAX], int left_offset);
00257 int ppm_draw_or_pref_line(int or_preferences[NMAX][NMAX], double or_selectivities[NMAX][NMAX], int left_offset);
00258 void ppm_draw_pixel(int xi, int yi, XColor color);
00259 XColor ppm_get_drawing_color(int lowi, int highi, int lowj, int highj, XColor set_color);
00260 int ppm_init_cortex_plot(int left_offset);
00261 int ppm_init_retina_plot(int left_offset);
00262 int ppm_init_histogram_plot(int symmetric, int left_offset);
00263 XColor ppm_lookup_color( int i, int j, double scaled_value, int subplot, int paper_based=Uninitialized);
00264 int ppm_scaled_cortex_height_offset(void);
00265 int ppm_scaled_cortex_plot_height( void );
00266 int ppm_scaled_cortex_plot_width( void );
00267 int ppm_scaled_cortex_unit_pixels( void );
00268 int ppm_scaled_histogram_bin_pixels( int num_bins );
00269 int ppm_scaled_histogram_height_offset(int num_bins );
00270 int ppm_scaled_histogram_plot_height(int num_bins );
00271 int ppm_scaled_histogram_plot_width( int num_bins, double scale );
00272 int ppm_scaled_retina_height_offset(void);
00273 int ppm_scaled_retina_plot_height( void );
00274 int ppm_scaled_retina_plot_width( void );
00275 int ppm_scaled_retina_unit_pixels( void );
00276 void ppm_write_header( FILE *file, const char *comments, int width, int height, int max_val );
00277 void rgb2hsv(XColor c, double *h, double *s, double *v );
00278 int ppm_write_pixel( FILE *file, XColor pixel, int max_val );
00279 template<class T>
00280 int ppm_write_image_to_file( T imagedata, const char* filename, const char *comments, int width, int height, int max_val );
00281
00282 int draw_outline(XColor color,
00283 int lowi, int highi, int lowj, int highj, int starti, int startj,
00284 int left_offset, int height_offset, int npixels_perunit, int outline_width,
00285 ppm_inside_test_ptr testfn, int int1, int int2, double float1, double
00286 float2, void *otherparams );
00287
00288
00289
00290
00291
00292
00293
00294 void ppm_init_hook( void )
00295 {
00296
00297 CONST_I(PPM_RYW, PPM_RYW, False,
00298 "Subplot type where the primary plot is encoded using a special colormap.\n"
00299 "When using this with ppm_paper_based_colors==False, inactive units\n"
00300 "are colored black, moderately active units are red, strongly activated\n"
00301 "units are colored yellow, and maximally activated units are colored\n"
00302 "white. Such a color scheme emphasizes peaks, particularly on video\n"
00303 "terminals. The colors are reversed when ppm_paper_based_colors is\n"
00304 "true, which isn't quite as effective on paper; in that case PPM_Grayscale\n"
00305 "is a better choice.");
00306
00307 CONST_I(PPM_Grayscale, PPM_GRAYSCALE, False,
00308 "Subplot type where monochrome luminance encodes value (e.g. activity).\n"
00309 "White represents maximum unless ppm_paper_based_colors is true.");
00310
00311 CONST_I(PPM_Orientation, PPM_ORIENTATION, False,
00312 "Subplot type where the primary plot is represented by saturation or luminance\n"
00313 "(depending on whether ppm_paper_based_colors is True or False, respectively),\n"
00314 "while the hue encodes orientation preference.\n\n"
00315
00316 "For retinal plots, each input pixel is colored by the nominal orientation of\n"
00317 "the object with the highest intensity value at that pixel. This value is\n"
00318 "not guaranteed to match the actual orientation judgment of a human observer,\n"
00319 "since e.g. a composite object will return its own orientation, even though\n"
00320 "the local orientation of a subobject may differ.");
00321
00322 CONST_I(PPM_OcularDominance,PPM_OCULARDOMINANCE,False,
00323 "Subplot type where the primary plot is represented by saturation or luminance\n"
00324 "(depending on whether ppm_paper_based_colors is True or False, respectively),\n"
00325 "while the hue encodes ocular dominance.");
00326
00327 CONST_I(PPM_SingleHue, PPM_SINGLEHUE, False,
00328 "Subplot type where the entire plot uses a hue specified by ppm_subplot_hue.");
00329
00330 CONST_I(PPM_None, PPM_NONE, False,
00331 "Subplot type where, depending upon the type of plot, the primary plot is\n"
00332 "represented by hue or luminance at full strength.");
00333
00334 CONST_I(PPM_Selectivity, PPM_SELECTIVITY, False,
00335 "Used for plots consisting of a primary dimension (e.g. orientation or\n"
00336 "ocular dominance), a selectivity associated with the primary\n"
00337 "dimension, and an optional level (e.g. activity or weight strength;\n"
00338 "assumed 1.0 if none). The primary dimension is represented by hue,\n"
00339 "while the other two dimensions are represented using luminance and\n"
00340 "saturation. The level effectively acts as a mask for a plot with the\n"
00341 "selectivity as saturation (ppm_paper_based_colors=False) or luminance\n"
00342 "(ppm_paper_based_colors=True). For ppm_paper_based_colors=False, the\n"
00343 "mask is implemented simply by using the level as the luminance. If\n"
00344 "ppm_paper_based_colors=True, the mask is implemented by using the\n"
00345 "level as the saturation and Max(1-scaled_level,selectivity) as the\n"
00346 "luminance. Both methods should be equivalent; they differ only\n"
00347 "because the color-expressing properties of luminance and saturation\n"
00348 "are opposites.");
00349
00350 CONST_I(PPM_WtScale_Fixed, PPM_WTSCALE_FIXED, False,
00351 "Scale the weights for all neurons by a constant multiplicative factor\n"
00352 "(ppm_afferent_multiplier or ppm_lateral_multiplier), regardless of their\n"
00353 "values or number of connections defined or active. This makes it simple to\n"
00354 "compare absolute weight values between different plots. However, it\n"
00355 "obscures differences in weight levels between adjacent units except at\n"
00356 "a single set of parameter values for which the multiplier has been\n"
00357 "chosen to be optimum.");
00358
00359 CONST_I(PPM_WtScale_Inhib,PPM_WTSCALE_INHIB,False,
00360 "Scale all weights by the number of inhibitory connections.\n"
00361 "This makes obvious the differences in weight strength between excitatory\n"
00362 "and inhibitory connections.");
00363
00364 CONST_I(PPM_WtScale_Count,PPM_WTSCALE_COUNT,False,
00365 "Scale the weights for a given neuron by the number of connections defined.\n"
00366 "Depending upon the values of ppm_weight_scale_init_count and\n"
00367 "ppm_weight_scale_max_count, this can make obvious the differences in weight\n"
00368 "value between weights to adjacent neurons or between different neurons or\n"
00369 "between the same neurons over time.");
00370
00371 CONST_I(PPM_WtScale_Active, PPM_WTSCALE_ACTIVE, False,
00372 "Scale the weights for a given neuron by the number of active (non-dead)\n"
00373 "connections for that neuron. This makes obvious the differences in\n"
00374 "weight levels between adjacent units, even when many units have been\n"
00375 "pruned, but obscures the increase in weight strength which pruning\n"
00376 "brings about.");
00377
00378 CONST_I(PPM_WtScale_PeakRelative,PPM_WTSCALE_PEAKRELATIVE, False,
00379 "Scale the weights for a given neuron so that the actual maximum value\n"
00380 "present is assigned the maximum value representable in a plot, while\n"
00381 "the minimum is set at zero. This makes local differences in value\n"
00382 "obvious without obscuring the distinction between zero and nonzero values.");
00383
00384 CONST_I(PPM_WtScale_Relative,PPM_WTSCALE_RELATIVE, False,
00385 "Scale the weights for a given neuron so that the actual maximum and minimum\n"
00386 "values present are assigned the minimum and maximum values representable in\n"
00387 "a plot. This always makes obvious the differences between weight values to\n"
00388 "adjacent units, which means that it is easy to use, but it also makes it\n"
00389 "impossible to compare absolute or relative weight values between different\n"
00390 "plots.");
00391
00392
00393
00394 PARAM_I(PARAM_INT, ppm_activity_subplot,0,PPM_MAX_SUBPLOT,
00395 "Secondary plot (using e.g. the hue value) for activity plots.\n\n"
00396 "Possible settings (starting with PPM_):\n"
00397 " RYW,Grayscale,OcularDominance,Orientation,Selectivity,SingleHue,None");
00398
00399 PARAM_I(PARAM_DOUBLE,ppm_activity_luminance_offset,0,1,
00400 "Amount to add to the computed value for activity plots using luminance.\n"
00401 "Normally this is zero, but if set to e.g. 0.25 in combination with a\n"
00402 "ppm_activity_subplot of e.g. orientation, the orientation map can be made\n"
00403 "out dimly even in areas where there is no activity. This can help relate\n"
00404 "the activity bubbles to their location on the map.");
00405
00406 PARAM_I(PARAM_BOOL, ppm_always_mark_neuron,False,True,
00407 "If true, always draw an outline around the neuron that is being plotted\n"
00408 "in e.g. a weight plot, and also draw an outline around the RF center of\n"
00409 "that neuron on the retina. Ordinarily the neuron is marked only when\n"
00410 "ppm_outline_weights is true and only in the inhibitory plots, since the\n"
00411 "center is usually clear on the smaller areas of the afferent and lateral\n"
00412 "excitatory plots.");
00413
00414 PARAM_L(PARAM_DOUBLE,ppm_master_scale,Uninitialized,
00415 "Ordinarily, this parameter will be set to 1.0, which means to automatically\n"
00416 "compute the minimum plot sizes that will show the full cortex and retina,\n"
00417 "regardless of the settings of ppm_cortex_scale, ppm_retina_scale,\n"
00418 "ppm_start_x,y,i,j, etc. If higher-resolution plots are desired, it can be\n"
00419 "set to a larger value, e.g. 2.0 to make all plots twice the normal size.\n"
00420 "Note that larger plots are not strictly multiples of the smaller ones,\n"
00421 "since the higher the resolution, the finer a line can be used for details\n"
00422 "such as outlines. To handle the scaling yourself, set this parameter to\n"
00423 "Uninitialized and set the aforementioned parameters as you desire. Note\n"
00424 "that like the other scaling parameters, it is of type double but\n"
00425 "currently only integer multiples are actually used.");
00426
00427 PARAM_L(PARAM_DOUBLE,ppm_afferent_multiplier,0,
00428 "Amount by which to multiply afferent weight value to get luminance value for\n"
00429 "plots.");
00430
00431 PARAM_I(PARAM_INT, ppm_afferent_subplot,0,PPM_MAX_SUBPLOT,
00432 "Secondary plot (using e.g. the hue value) for afferent weight plots.\n\n"
00433 "Possible settings (starting with PPM_):\n"
00434 " RYW,Grayscale,OcularDominance,Orientation,Selectivity,SingleHue,None");
00435
00436 PARAM_I(PARAM_BOOL, ppm_always_draw_point,False,True,
00437 "Whether ppm_draw_line_at_angle() always draws at least one point, e.g. when \n"
00438 "plotting orientation using lines.");
00439
00440 PARAM_I(PARAM_DOUBLE,ppm_bg_B,Uninitialized,1,
00441 "Blue component of color of background and border areas; default is white or\n"
00442 "black depending on ppm_paper_based_colors.");
00443
00444 PARAM_I(PARAM_DOUBLE,ppm_bg_G,Uninitialized,1,
00445 "Green component of color of background and border areas; default is white\n"
00446 "or black depending on ppm_paper_based_colors.");
00447
00448 PARAM_I(PARAM_DOUBLE,ppm_bg_R,Uninitialized,1,
00449 "Red component of color of background and border areas; default is white or\n"
00450 "black depending on ppm_paper_based_colors.");
00451
00452 PARAM_L(PARAM_INT, ppm_border,0,
00453 "Number of pixels between subsequent plots in the same image; defaults to 3%%\n"
00454 "of the image size, subject to a minimum of two.");
00455
00456 PARAM_I(PARAM_INT, ppm_color_key_num,0,or_num_angles,
00457 "The number of oriented bars to use in a color key when ppm_color_keys is true.");
00458
00459 PARAM_I(PARAM_BOOL, ppm_color_keys,Uninitialized,True,
00460 "Whether or not to draw a color key after a color plot. By default will draw\n"
00461 "one if color-coded orientation was used.");
00462
00463 PARAM_I(PARAM_BOOL, ppm_combine_alternate_eyes,False,True,
00464 "If there is more than one eye (and an even number total), plot them by twos\n"
00465 "where the second half of each pair is subtracted from the first. This is\n"
00466 "useful for e.g. ON and OFF cell layers created using Blur_DoGGoD. This\n"
00467 "option will need more work to be very useful except with a very limited\n"
00468 "range of absolute unnormalized weights, since right now weights are\n"
00469 "normalized independently between the two subtracted values (which has\n"
00470 "poor results.)");
00471
00472 PARAM_L(PARAM_DOUBLE,ppm_cortex_scale,Uninitialized,
00473 "Scaling factor when plotting cortex. Defaults to autoscale to match retina.\n"
00474 "At the moment only integer values are used, to ensure that plots always devote\n"
00475 "the same number of pixels to each neuron (to prevent confusion). As a result\n"
00476 "plots will not be shown if the scale is less than 1. This restriction may be\n"
00477 "relaxed in the future.");
00478
00479 PARAM_I(PARAM_INT, ppm_end_i,Uninitialized,NMAX,
00480 "By default, the entire cortex is plotted, but when ppm_master_scale is\n"
00481 "Uninitialized, this parameter is one higher than the last pixel plotted\n"
00482 "in the X direction.");
00483
00484 PARAM_I(PARAM_INT, ppm_end_j,Uninitialized,NMAX,
00485 "By default, the entire cortex is plotted, but when ppm_master_scale is\n"
00486 "Uninitialized, this parameter is one higher than the last pixel plotted\n"
00487 "in the Y direction.");
00488
00489 PARAM_I(PARAM_INT, ppm_end_x,Uninitialized,RNMAX,
00490 "By default, the entire retina is plotted, but when ppm_master_scale is\n"
00491 "Uninitialized, this parameter is one higher than the last pixel plotted\n"
00492 "in the X direction.");
00493
00494 PARAM_I(PARAM_INT, ppm_end_y,Uninitialized,RNMAX,
00495 "By default, the entire retina is plotted, but when ppm_master_scale is\n"
00496 "Uninitialized, this parameter is one higher than the last pixel plotted\n"
00497 "in the Y direction.");
00498
00499 PARAM_L(PARAM_DOUBLE,ppm_histo_scale_factor,0,
00500 "Ratio applied to the size of a cortex plot to get the width of an accompanying\n"
00501 "histogram.");
00502
00503 PARAM_I(PARAM_DOUBLE,ppm_histo_percentage_range,0,100,
00504 "Range of an activity histogram, peak to peak, as a percentage.");
00505
00506 PARAM_I(PARAM_BOOL, ppm_histograms,False,True,
00507 "Whether to include activity histograms with plots, if orientation data is\n"
00508 "available. Doesn't currently support OD histograms, but could do so easily.");
00509
00510 PARAM_L(PARAM_INT, ppm_interior_border,0,
00511 "Number of pixels to skip between internal image features, e.g. orientation\n"
00512 "lines.");
00513
00514 PARAM_I(PARAM_BOOL, ppm_interior_outline,False,True,
00515 "Whether or not to outline smaller maps which appear inside of larger ones,\n"
00516 "e.g. for plot_afferent_weight_map");
00517
00518 PARAM_I(PARAM_STRING,ppm_image_viewer,0,MAXFILENAMELENGTH,
00519 "External program to spawn when an image is created, ppm_spawn_viewer is\n"
00520 "true, and running_remotely is false.");
00521
00522 PARAM_L(PARAM_DOUBLE,ppm_lateral_multiplier,0,
00523 "Amount by which to multiply lateral weight value to get luminance value for\n"
00524 "plots.");
00525
00526 PARAM_I(PARAM_INT, ppm_lateral_subplot,0,PPM_MAX_SUBPLOT,
00527 "Secondary plot (using e.g. the hue value) for lateral weight plots.\n\n"
00528 "Possible settings (starting with PPM_):\n"
00529 " RYW,Grayscale,OcularDominance,Orientation,Selectivity,SingleHue,None");
00530
00531 PARAM_I(PARAM_DOUBLE,ppm_line_B,Uninitialized,1,
00532 "Blue component of color of lines to be drawn on an image;\n"
00533 "default is dynamically chosen to have good contrast with the area of the\n"
00534 "image being overwritten.");
00535
00536 PARAM_I(PARAM_DOUBLE,ppm_line_G,Uninitialized,1,
00537 "Green component of color of lines to be drawn on an image;\n"
00538 "default is dynamically chosen to have good contrast with the area of the\n"
00539 "image being overwritten.");
00540
00541 PARAM_I(PARAM_DOUBLE,ppm_line_R,Uninitialized,1,
00542 "Red component of color of lines to be drawn on an image; default is dynamically\n"
00543 "chosen to have good contrast with the area of the image being overwritten.");
00544
00545 PARAM_I(PARAM_INT, ppm_line_orientation_subplot,0,PPM_MAX_SUBPLOT,
00546 "Secondary plot (using the line length of orientation lines) for orientation\n"
00547 "map plots.\n\n"
00548 "Possible settings (starting with PPM_): Selectivity,None");
00549
00550 PARAM_I(PARAM_BOOL, ppm_line_plots,False,True,
00551 "Whether to draw line plots (e.g. for orientation or weights) as opposed to \n"
00552 "(or in addition to) shaded plots.");
00553
00554 PARAM_L(PARAM_DOUBLE,ppm_line_selectivity_multiplier,0,
00555 "Amount by which to multiply orientation selectivity to get line length for\n"
00556 "plots.");
00557
00558 PARAM_L(PARAM_DOUBLE,ppm_luminance_multiplier,0,
00559 "Amount by which to multiply activity to get luminance value for plots.");
00560
00561 PARAM_I(PARAM_BOOL, ppm_minimal_outline,False,True,
00562 "Whether to outline the active lateral weights only, or all of those\n"
00563 "currently allowed. If true, outlines only those units with weights greater\n"
00564 "than ppm_weight_threshold.");
00565
00566 PARAM_L(PARAM_INT, ppm_neuron_ioffset_line,0,
00567 "Horizontal offset for skipping when ppm_neuron_skip_line is not 1. This \n"
00568 "determines where the cycles start. It is usually zero but can be set \n"
00569 "to some other value X such that (0 < X < ppm_neuron_skip_line) to ensure\n"
00570 "that a particular neuron is actually drawn.");
00571
00572 PARAM_L(PARAM_INT, ppm_neuron_joffset_line,0,
00573 "Vertical offset for skipping when ppm_neuron_skip_line is not 1. This \n"
00574 "determines where the cycles start. It is usually zero but can be set \n"
00575 "to some other value X such that (0 < X < ppm_neuron_skip_line) to ensure\n"
00576 "that a particular neuron is actually drawn.");
00577
00578 PARAM_L(PARAM_INT, ppm_neuron_skip_line,1,
00579 "Draw every nth neuron only, for line plots.");
00580
00581 PARAM_L(PARAM_INT, ppm_neuron_skip_aff,1,
00582 "Draw every nth neuron only, for afferent weight map plots.");
00583
00584 PARAM_I(PARAM_INT, ppm_ocular_dominance_subplot,0,PPM_MAX_SUBPLOT,
00585 "Type of plot for ocular dominance map plots.\n\n"
00586 "Possible settings (starting with PPM_):\n"
00587 " RYW,Grayscale,Selectivity,SingleHue,None");
00588
00589 PARAM_I(PARAM_INT, ppm_orientation_subplot,0,PPM_MAX_SUBPLOT,
00590 "Secondary plot (using e.g. the luminance value) for orientation map plots.\n\n"
00591 "Possible settings (starting with PPM_): Grayscale,Selectivity,None\n"
00592 "See the documentation for those options for more details.");
00593
00594 PARAM_I(PARAM_BOOL, ppm_outline_retina,False,True,
00595 "Whether to draw a line around the active area of the retina, i.e. the area\n"
00596 "not included in the retina_edge_buffer region, when retina_edge_buffer is\n"
00597 "nonzero. See also ppm_retina_edge_buffer_suppress.");
00598
00599 PARAM_I(PARAM_BOOL, ppm_outline_weights,False,True,
00600 "Whether to draw a line around the active weight area plotted on maps of the\n"
00601 "cortex.");
00602
00603 PARAM_L(PARAM_INT, ppm_outline_width,0,
00604 "Number of pixels to use for intra-picture outlines.");
00605
00606 PARAM_I(PARAM_BOOL, ppm_paper_based_colors,False,True,
00607 "Usually, the colors are suitable for video, with black backgrounds and \n"
00608 "luminance encoding the weight or activation level. For paper plots, this\n"
00609 "parameter can be set to 1 so that white backgrounds are used and saturation\n"
00610 "will encode the level.");
00611
00612 PARAM_I(PARAM_BOOL, ppm_paper_based_retina,Uninitialized,True,
00613 "If set to Boolean value other than Uninitialized, whether to consider\n"
00614 "ppm_paper_based_colors true for the retina regardless of its global value.");
00615
00616 PARAM_I(PARAM_DOUBLE,ppm_reference_angle,0,180,
00617 "When setting luminance for monochrome orientation plots, this will be the\n"
00618 "angle (in degrees) at which luminance is zero.");
00619
00620 PARAM_I(PARAM_STRING,ppm_remote_viewer,0,MAXFILENAMELENGTH,
00621 "External program to spawn when an image is created, ppm_spawn_viewer is\n"
00622 "true, and running_remotely is true.");
00623
00624 PARAM_L(PARAM_DOUBLE,ppm_retina_scale,Uninitialized,
00625 "Scaling factor when plotting retina. Defaults to autoscale to match cortex.\n"
00626 "At the moment only integer values are used, to ensure that plots always devote\n"
00627 "the same number of pixels to each retinal unit (to prevent confusion). As a\n"
00628 "result plots will not be shown if the scale is less than 1. This restriction\n"
00629 "may be relaxed in the future.");
00630
00631 PARAM_I(PARAM_INT, ppm_retina_subplot,0,PPM_MAX_SUBPLOT,
00632 "Secondary plot (using e.g. the hue value) for retinal activation plots.\n\n"
00633 "Possible settings (starting with PPM_):\n"
00634 " RYW,Grayscale,Orientation,SingleHue,None");
00635
00636 PARAM_I(PARAM_BOOL, ppm_retina_edge_buffer_suppress,False,True,
00637 "If true, will only plot the active area of the retina, i.e. the area\n"
00638 "not included in the retina_edge_buffer region. See also ppm_outline_retina.");
00639
00640 PARAM_L(PARAM_DOUBLE,ppm_selectivity_multiplier,0,
00641 "Amount by which to multiply orientation selectivity to get luminance value\n"
00642 "for plots.");
00643
00644 PARAM_I(PARAM_BOOL, ppm_shaded_plots,False,True,
00645 "Whether to draw shaded plots, including color and mono plots (e.g. for \n"
00646 "orientation). (Not necessarily exclusive of ppm_line_plots.)");
00647
00648 PARAM_I(PARAM_BOOL, ppm_spawn_viewer,Uninitialized,True,
00649 "Alias for spawn_viewer; whether to spawn an external program (specified by\n"
00650 "ppm_image_viewer) to view an image when it is created.");
00651
00652 PARAM_I(PARAM_BOOL, ppm_spawn_independent_viewers,False,True,
00653 "When ppm_spawn_viewer is true, whether to spawn for every image, or just\n"
00654 "the first one.");
00655
00656 PARAM_I(PARAM_INT, ppm_start_i,Uninitialized,NMAX,
00657 "By default, the entire cortex is plotted, but when ppm_master_scale is\n"
00658 "Uninitialized, this parameter sets the first pixel plotted in the X direction.");
00659
00660 PARAM_I(PARAM_INT, ppm_start_j,Uninitialized,NMAX,
00661 "By default, the entire cortex is plotted, but when ppm_master_scale is\n"
00662 "Uninitialized, this parameter sets the first pixel plotted in the Y direction.");
00663
00664 PARAM_I(PARAM_INT, ppm_start_x,Uninitialized,RNMAX,
00665 "By default, the entire retina is plotted, but when ppm_master_scale is\n"
00666 "Uninitialized, this parameter sets the first pixel plotted in the X direction.");
00667
00668 PARAM_I(PARAM_INT, ppm_start_y,Uninitialized,RNMAX,
00669 "By default, the entire retina is plotted, but when ppm_master_scale is\n"
00670 "Uninitialized, this parameter sets the first pixel plotted in the Y direction.");
00671
00672 PARAM_I(PARAM_DOUBLE,ppm_subplot_hue,Uninitialized,1,
00673 "The hue (in terms of Hue, Saturation, and Value) to use when a subplot is\n"
00674 "set to PPM_SingleHue.");
00675
00676 PARAM_I(PARAM_INT, ppm_ui,Uninitialized,NMAX,
00677 "Denotes x-coordinate of unit to graph as a secondary plot, e.g. as lateral\n"
00678 "weights on top of another plot.");
00679
00680 PARAM_I(PARAM_INT, ppm_uj,Uninitialized,NMAX,
00681 "Denotes y-coordinate of unit to graph as a secondary plot, e.g. as lateral\n"
00682 "weights on top of another plot.");
00683
00684 PARAM_I(PARAM_DOUBLE,ppm_value_offset,0,1,
00685 "Determines the offset of the range of values used for HSV coordinates.\n"
00686 "Not always used; check to make sure for a particular plot.");
00687
00688 PARAM_I(PARAM_DOUBLE,ppm_value_range,0,1,
00689 "Determines the range of Values used for HSV coordinates. Not always used;\n"
00690 "check to make sure for a particular plot.");
00691
00692 PARAM_N(PARAM_DOUBLE,ppm_weight_threshold,
00693 "Strength of weight to consider active for weight plots.");
00694
00695 PARAM_I(PARAM_BOOL, ppm_weight_scale_init_count,False,True,
00696 "When plotting weights on a scale relative to the number of connections\n"
00697 "(ppm_weight_scale_type == Count), whether to base the scale on\n"
00698 "the number of connections defined at the start of the simulation, as\n"
00699 "opposed to the number currently defined. If set to True, makes obvious\n"
00700 "the increase in weight strength when a radius is decreased, but obscures\n"
00701 "the differences between the connections of a given unit to adjacent units.\n"
00702 "Only important for a connection type whose radius changes over time.");
00703
00704 PARAM_I(PARAM_BOOL, ppm_weight_scale_max_count,False,True,
00705 "When plotting weights on a scale relative to the number of connections\n"
00706 "(ppm_weight_scale_type == Count or Inhib), whether to base the scale on\n"
00707 "the maximum number of connections of the given type possible for any\n"
00708 "neuron, or else to use the number possible for this particular neuron.\n"
00709 "If set to True, makes obvious any differences in weight values from a\n"
00710 "given unit to adjacent units, while obscuring the different absolute\n"
00711 "weight values between units in the center and those near the border.\n"
00712 "Only important for units near the border.");
00713
00714 PARAM_I(PARAM_INT, ppm_weight_scale_type,0,PPM_MAX_WTSCALE,
00715 "Type of scaling to use for weight plots. Possible settings (starting with\n"
00716 "PPM_WtScale_):\n\n"
00717
00718 " Fixed\n"
00719 " Inhib\n"
00720 " Count\n"
00721 " Active\n"
00722 " PeakRelative\n"
00723 " Relative\n\n"
00724
00725 "The first type uses a fixed scale for all lateral weight plots (determined\n"
00726 "by ppm_lateral multiplier), and another fixed scale for all afferent weight\n"
00727 "plots (determined by ppm_afferent_multiplier). This makes it simple to\n"
00728 "compare different plots, since they will be on the same scale, but often\n"
00729 "individual plots will fail to show detail in the differences between\n"
00730 "adjacent units' weight values. The last type has the opposite virtues and\n"
00731 "faults: each individual plot shows the maximum possible detail, but the\n"
00732 "absolute values of the weights are impossible to determine. Those types in\n"
00733 "between reflect a different setting of this tradeoff between highlighting\n"
00734 "differences in a single plot, versus being able to compare plots and\n"
00735 "determine absolute weight levels.\n\n"
00736
00737 "When using any of these types besides PPM_WtScale_Fixed, be sure to keep in\n"
00738 "mind that the absolute weight values depend upon the number of connections of\n"
00739 "that type active for that neuron, which in turn depends upon the connection\n"
00740 "radius, whether connections are square or circular, how close the neuron is\n"
00741 "to the border, and the connection death level. See the parameters\n"
00742 "ppm_weight_scale_init_count and ppm_weight_scale_max_count to change\n"
00743 "how the scaling depends on the connection counts.\n\n"
00744
00745 "The effective values of cortical weights also depend upon the cortical weight\n"
00746 "scaling factors gamma_exc and gamma_inh; none of the weight plots currently\n"
00747 "take these parameters' values into account.");
00748 }
00749
00750
00751
00752
00753
00754
00759 void ppm_bitmap_initialize(void)
00760 {
00761
00762 const double bg_default = (ppm_paper_based_colors? 0.0 : 1.0);
00763 const double bg_R = (ppm_bg_R>=0 ? ppm_bg_R : bg_default);
00764 const double bg_G = (ppm_bg_G>=0 ? ppm_bg_G : bg_default);
00765 const double bg_B = (ppm_bg_B>=0 ? ppm_bg_B : bg_default);
00766
00767
00768 ppm_background_color.red = (int)(bg_R*HIGHEST_COLOR_LEVEL);
00769 ppm_background_color.green = (int)(bg_G*HIGHEST_COLOR_LEVEL);
00770 ppm_background_color.blue = (int)(bg_B*HIGHEST_COLOR_LEVEL);
00771
00772 00773 00774 00775 00776 00777
00778 const double fg_default = (ppm_paper_based_colors? 1.0 : 0.0);
00779 const double fg_R = (ppm_line_R>=0 ? ppm_line_R : fg_default);
00780 const double fg_G = (ppm_line_G>=0 ? ppm_line_G : fg_default);
00781 const double fg_B = (ppm_line_B>=0 ? ppm_line_B : fg_default);
00782
00783
00784 ppm_foreground_color.red = (int)(fg_R*HIGHEST_COLOR_LEVEL);
00785 ppm_foreground_color.green = (int)(fg_G*HIGHEST_COLOR_LEVEL);
00786 ppm_foreground_color.blue = (int)(fg_B*HIGHEST_COLOR_LEVEL);
00787 ppm_foreground_color.flags =
00788 (((ppm_line_R < 0) || (ppm_line_G < 0) || (ppm_line_B < 0)) ?
00789 BadPixel : 0);
00790
00791
00792
00793 ppm_clear_image(ppm_background_color.red,ppm_background_color.green,ppm_background_color.blue);
00794
00795
00796 if (ppm_master_scale != Uninitialized || ppm_start_i == Uninitialized) ppm_start_i = 0;
00797 if (ppm_master_scale != Uninitialized || ppm_start_j == Uninitialized) ppm_start_j = 0;
00798 if (ppm_master_scale != Uninitialized || ppm_end_i == Uninitialized) ppm_end_i = N;
00799 if (ppm_master_scale != Uninitialized || ppm_end_j == Uninitialized) ppm_end_j = N;
00800
00801
00802 {
00803 int buffer = (ppm_retina_edge_buffer_suppress ? retina_edge_buffer : 0);
00804 if (ppm_master_scale != Uninitialized || ppm_start_x == Uninitialized) ppm_start_x = 0+buffer;
00805 if (ppm_master_scale != Uninitialized || ppm_start_y == Uninitialized) ppm_start_y = 0+buffer;
00806 if (ppm_master_scale != Uninitialized || ppm_end_x == Uninitialized) ppm_end_x = RN-buffer;
00807 if (ppm_master_scale != Uninitialized || ppm_end_y == Uninitialized) ppm_end_y = RN-buffer;
00808 }
00809
00810
00811 create_colormap_RGB(colors, ncolors);
00812 }
00813
00814
00815
00817 int ppm_presentation_height(void)
00818 {
00819 const double masterscale = (ppm_master_scale != Uninitialized ? ppm_master_scale : 1.0);
00820 const int active_N = ppm_end_j-ppm_start_j;
00821
00822 const int active_RN = ppm_end_y-ppm_start_y;
00823 const int mapping_start_y = MAX(retina_edge_buffer, ppm_start_y);
00824 const int mapping_end_y = MIN(RN-retina_edge_buffer, ppm_end_y);
00825 const int mapping_height = mapping_end_y - mapping_start_y;
00826
00827 int height,cortex_height,retina_height;
00828
00829
00830 if (ppm_master_scale != Uninitialized || ppm_cortex_scale == Uninitialized)
00831 ppm_cortex_scale = (active_N>mapping_height ? masterscale : masterscale*mapping_height/(1.0*active_N ));
00832 cortex_height=((int)ppm_cortex_scale)*active_N;
00833
00834 if (ppm_master_scale != Uninitialized || ppm_retina_scale == Uninitialized)
00835 ppm_retina_scale = (active_N<mapping_height ? masterscale : masterscale*active_N/(1.0*mapping_height));
00836 retina_height=((int)ppm_retina_scale)*active_RN;
00837
00838
00839 height = ppm_border + MAX(cortex_height,retina_height) + ppm_border;
00840
00841 if (height > IMG_SIZE_Y) {
00842 ipc_notify(IPC_ALL,IPC_ERROR,"ppm_presentation_height: Height %d is too large for image of %d; aborting",
00843 height, (int)IMG_SIZE_Y);
00844 return 0;
00845 }
00846 else {
00847 ppm_height = height;
00848 return height;
00849 }
00850 }
00851
00852
00853
00854
00855
00856
00857
00858
00859
00860
00861
00862
00863 LOff ppm_draw_activity(double activity[NMAX][NMAX], int left_offset)
00864 {
00865 const int width = ppm_init_cortex_plot(left_offset);
00866 int i,j;
00867 double max_value=-1e12;
00868 double min_value=+1e12;
00869
00870 if (width)
00871 for( i=ppm_start_i; i<ppm_end_i; i++)
00872 for(j=ppm_start_j; j<ppm_end_j; j++) {
00873 const double val = activity[i][j];
00874 const double value = ppm_activity_luminance_offset + val;
00875
00876 if (val > max_value) max_value = val;
00877 if (val < min_value) min_value = val;
00878
00879 draw_cortex_unit(ppm_lookup_color(i,j,ppm_luminance_multiplier*
00880 value,ppm_activity_subplot),
00881 i,j,False,left_offset);
00882 }
00883
00884 ipc_notify(IPC_ALL,IPC_VERBOSE,"ppm_draw_activity: Values ranged from %g to %g",
00885 min_value,max_value);
00886
00887 return width;
00888 }
00889
00890
00891
00892 LOff ppm_draw_od_pref(double od_pref_array[NMAX][NMAX], int left_offset)
00893 {
00894 const int width = ppm_init_cortex_plot(left_offset);
00895 int i,j;
00896
00897 if (width)
00898 for( i=ppm_start_i; i < ppm_end_i; i++)
00899 for(j= ppm_start_j; j < ppm_end_j; j++)
00900 draw_cortex_unit(ppm_lookup_color(i,j,od_pref_array[i][j],
00901 ppm_ocular_dominance_subplot),
00902 i,j,False,left_offset);
00903 return width;
00904 }
00905
00906
00907
00908 LOff ppm_draw_or_pref(int or_preferences[NMAX][NMAX],
00909 double or_selectivities[NMAX][NMAX],
00910 bool selectivity_only, int left_offset)
00911 {
00912 const int width = ppm_init_cortex_plot(left_offset);
00913 int i,j;
00914 int badpixels = 0;
00915
00916 if (width)
00917 for( i=ppm_start_i; i < ppm_end_i; i++)
00918 for(j= ppm_start_j; j < ppm_end_j; j++){
00919
00920 double hue = NOHUE;
00921 double saturation = 1.0;
00922 double value = 1.0;
00923 int orp = or_preferences[i][j];
00924 double scaled_select = CROP(0.0,1.0,or_selectivities[i][j]*ppm_selectivity_multiplier);
00925
00926 XColor color;
00927
00928
00929 if (orp == -1) orp = 0;
00930
00931
00932 if (selectivity_only) {
00933 saturation = 0.0;
00934 value = (ppm_paper_based_colors ? scaled_select: 1.0-scaled_select);
00935 if (value > 1.0 || value < 0.0)
00936 cout << value << "\t";
00937 }
00938 else {
00939
00940
00941 if ( (orp<0) || (OR_PREF_TO_DEGREES(orp)>180.0) ) {
00942 badpixels++;
00943 hue = NOHUE;
00944 }
00945 else hue = OR_PREF_TO_DEGREES(orp)/180.0;
00946
00947 switch (ppm_orientation_subplot) {
00948 case PPM_SELECTIVITY:
00949 if (ppm_paper_based_colors) value = scaled_select;
00950 else saturation = scaled_select;
00951
00952 break;
00953 case PPM_GRAYSCALE: {
00954
00955 float ord = OR_PREF_TO_DEGREES(orp);
00956
00957 float or_radians = CONSTRAIN_ANGLE(DEGREES_TO_RADIANS(ord-ppm_reference_angle));
00958 saturation = 0.0;
00959
00960 if (or_radians<M_PI/2) value = ( or_radians )/(M_PI/2);
00961 else value = fabs( M_PI-or_radians )/(M_PI/2);
00962
00963
00964 value = CROP(0,1.0,ppm_value_range*value+ppm_value_offset);
00965
00966
00967 if (ppm_paper_based_colors) value = 1.0-value;
00968
00969 break;
00970 }
00971
00972 case PPM_NONE:
00973 break;
00974
00975 default:
00976 ipc_notify(IPC_ONE,IPC_WARNING,"Unsupported ppm_orientation_subplot: %d",
00977 ppm_orientation_subplot);
00978 }
00979 }
00980
00981 hsv2rgb(hue, saturation, value, &color);
00982
00983 draw_cortex_unit(color,i,j,False,left_offset);
00984 }
00985
00986
00987 if (badpixels > 0)
00988 ipc_notify(IPC_ALL,IPC_WARNING,"ppm_draw_or_pref: There were %d bad pixels",badpixels);
00989
00990 return width;
00991 }
00992
00993
00994
00996 LOff ppm_draw_or_pref_line(int or_preferences[NMAX][NMAX],
00997 double or_selectivities[NMAX][NMAX],
00998 int left_offset)
00999 {
01000 const int scaled_width = ppm_scaled_cortex_plot_width();
01001 const int height_offset = ppm_scaled_cortex_height_offset();
01002 const int npixels_perunit = ppm_scaled_cortex_unit_pixels();
01003
01004 int i,j;
01005 int badpixels = 0;
01006
01007 if (!canExtendWidthTo(left_offset + scaled_width))
01008 return 0;
01009
01010
01011 for( i=ppm_start_i; i < ppm_end_i; i++){
01012 const int square_left_offset = left_offset + (i-ppm_start_i)*npixels_perunit;
01013
01014 for(j= ppm_start_j; j < ppm_end_j; j++){
01015 const int square_height_offset = height_offset + (j-ppm_start_j)*npixels_perunit;
01016 double length;
01017
01018
01019 if ( ppm_line_plots &&
01020 ( ((i+ppm_neuron_ioffset_line) % ppm_neuron_skip_line) == 0) &&
01021 ( ((j+ppm_neuron_joffset_line) % ppm_neuron_skip_line) == 0) ) {
01022
01023 int orp = or_preferences[i][j];
01024
01025 length = ppm_neuron_skip_line*npixels_perunit-ppm_interior_border;
01026
01027 01028 01029
01030 if (orp == -1) orp = 0;
01031
01032 switch (ppm_line_orientation_subplot) {
01033 case PPM_SELECTIVITY:
01034 length *= or_selectivities[i][j]*ppm_line_selectivity_multiplier;
01035 break;
01036 case PPM_NONE:
01037 break;
01038 default:
01039 ipc_notify(IPC_ONE,IPC_WARNING,"Unsupported ppm_line_orientation_subplot: %d",
01040 ppm_line_orientation_subplot);
01041 }
01042
01043 ppm_draw_line_at_angle(square_left_offset + ppm_neuron_skip_line*npixels_perunit/2,
01044 square_height_offset + ppm_neuron_skip_line*npixels_perunit/2,
01045 DEGREES_TO_RADIANS(OR_PREF_TO_DEGREES(orp)),
01046 length, ppm_outline_width,
01047 ppm_foreground_color);
01048 }
01049 }
01050 }
01051
01052 if (badpixels > 0)
01053 ipc_notify(IPC_ALL,IPC_WARNING,"ppm_draw_or_pref_line: There were %d bad pixels",badpixels);
01054
01055 return scaled_width;
01056 }
01057
01058
01059
01060 LOff ppm_draw_lateral_weights(int ui, int uj, l_weight *weights, int radius,
01061 int ar_width, int left_offset,
01062 int isInhWts, int mark_neuron)
01063 {
01064 const int lowi = MAX(ui-radius, 0);
01065 const int highi = MIN(ui+radius,N-1);
01066 const int lowj = MAX(uj-radius, 0);
01067 const int highj = MIN(uj+radius,N-1);
01068
01069 const int width = ppm_init_cortex_plot(left_offset);
01070
01071 double scale_factor;
01072 double scale_offset;
01073 int i,j;
01074
01075 double max_value=-1e12;
01076 double min_value=+1e12;
01077
01078 if (!width)
01079 return width;
01080
01081 compute_weight_scale(ui,uj,N,circular_lat_wts,
01082 radius,ar_width,weights,True,
01083 &scale_factor,&scale_offset);
01084
01085 for( i=ppm_start_i; i < ppm_end_i; i++)
01086 for(j= ppm_start_j; j < ppm_end_j; j++){
01087 const double none = (i<lowi || i>highi || j<lowj || j>highj);
01088 const double val = (none? 0 : weights[LAT_INDEX(ui,uj,i,j,radius,ar_width)]);
01089 const double level = MAX(0,val);
01090 const double value = (level < ppm_weight_threshold ? 0 :
01091 (level+scale_offset)*scale_factor);
01092
01093 if (!none && val > max_value) max_value = val;
01094 if (!none && val < min_value) min_value = val;
01095
01096 draw_cortex_unit(ppm_lookup_color(i,j,value,
01097 ppm_lateral_subplot),
01098 i,j,False,left_offset);
01099 }
01100
01101 if (ppm_outline_weights) {
01102 if (isInhWts && ppm_minimal_outline)
01103 draw_outline_on_cortex( ui, uj, radius, left_offset, inhWeightAbove);
01104 else if (circular_lat_wts)
01105 draw_outline_on_cortex( ui, uj, radius, left_offset, isInsideCircle);
01106 else
01107 draw_box_outline_on_cortex( ui+0.5, uj+0.5, radius+0.5, left_offset);
01108 }
01109
01110 if (mark_neuron)
01111 draw_box_outline_on_cortex( ui+0.5, uj+0.5, 0.5, left_offset);
01112
01113 ipc_notify(IPC_ALL,IPC_VERBOSE,"ppm_lateral_weights: Values ranged from %g to %g",
01114 min_value,max_value);
01115
01116 return width;
01117 }
01118
01119
01120
01126 LOff ppm_draw_retina(int eye, double input_v[RNMAX*RNMAX], int left_offset)
01127 {
01128 const int width = ppm_init_retina_plot(left_offset);
01129 int i,j;
01130 (void)eye;
01131 double max_value=-1e12;
01132 double min_value=+1e12;
01133
01134 if (width)
01135 for( i=ppm_start_x; i < ppm_end_x; i++)
01136 for(j= ppm_start_y; j < ppm_end_y; j++) {
01137 const double val = input_v[INP_INDEX(0,i,j)];
01138 const double value = MAX(0,val);
01139 XColor color;
01140
01141 if (val > max_value) max_value = val;
01142 if (val < min_value) min_value = val;
01143
01144 if (ppm_retina_subplot == PPM_ORIENTATION) {
01145 #ifdef NO_INPUTS
01146 double angle = 0;
01147 #else
01148 double angle = inputs->angle_of_object_at_location(i,j,eye);
01149 #endif
01150 if (ppm_paper_based_colors)
01151 hsv2rgb(angle/M_PI, value, 1.0, &color);
01152 else
01153 hsv2rgb(angle/M_PI, 1.0, value, &color);
01154 }
01155 else
01156 color = ppm_lookup_color(i*N/RN,j*N/RN,
01157 value,ppm_retina_subplot,ppm_paper_based_retina);
01158
01159 draw_retina_unit(color,i,j,False,left_offset);
01160 }
01161
01162
01163 if (width && ppm_outline_retina && !ppm_retina_edge_buffer_suppress && retina_edge_buffer > 0)
01164 draw_box_outline_on_retina( RN/2.0, RN/2.0, (RN-2.0*retina_edge_buffer)/2.0, left_offset);
01165
01166 ipc_notify(IPC_ALL,IPC_VERBOSE,"ppm_draw_retina: Values ranged from %g to %g",
01167 min_value,max_value);
01168
01169
01170 return width;
01171 }
01172
01173
01174
01175 LOff ppm_draw_afferent_weights(int center_x, int center_y,
01176 a_weight weights[WTMAX][WTMAX],
01177 int ui, int uj, int left_offset)
01178 {
01179 const int lowi = MAX(center_x-rf_radius,0 );
01180 const int highi = MIN(center_x+rf_radius,RN-1);
01181 const int lowj = MAX(center_y-rf_radius,0 );
01182 const int highj = MIN(center_y+rf_radius,RN-1);
01183
01184 const int width = ppm_init_retina_plot(left_offset);
01185
01186 double scale_factor;
01187 double scale_offset;
01188 int i,j;
01189
01190 double max_value=-1e12;
01191 double min_value=+1e12;
01192
01193 if (!width)
01194 return width;
01195
01196 compute_weight_scale(center_x,center_y,RN,circular_aff_wts,
01197 rf_radius,rf_radius*2+1,weights,False,
01198 &scale_factor, &scale_offset);
01199
01200 for( i=ppm_start_x; i < ppm_end_x; i++)
01201 for(j= ppm_start_y; j < ppm_end_y; j++) {
01202 const double none = (i<lowi || i>highi || j<lowj || j>highj);
01203 const double val = (none ? 0 : weights[i-lowi][j-lowj]);
01204 const double level = MAX(0,val);
01205 const double value = (level < ppm_weight_threshold ? 0 :
01206 (level+scale_offset)*scale_factor);
01207
01208 if (!none && val > max_value) max_value = val;
01209 if (!none && val < min_value) min_value = val;
01210
01211 draw_retina_unit(ppm_lookup_color(ui,uj,value,ppm_afferent_subplot),
01212 i,j,False,left_offset);
01213 }
01214
01215 if (ppm_outline_weights)
01216 if (circular_aff_wts)
01217 draw_outline_on_retina(cortex_map[ui][uj].centerx, cortex_map[ui][uj].centery,
01218 rf_radius, left_offset, isInsideCircle);
01219 else
01220 draw_box_outline_on_retina(cortex_map[ui][uj].centerx+0.5, cortex_map[ui][uj].centery+0.5,
01221 rf_radius+0.5, left_offset);
01222
01223
01224 if (width && ppm_outline_retina && !ppm_retina_edge_buffer_suppress && retina_edge_buffer > 0)
01225 draw_box_outline_on_retina( RN/2.0, RN/2.0, (RN-2.0*retina_edge_buffer)/2.0, left_offset);
01226
01227 if (ppm_always_mark_neuron)
01228 draw_box_outline_on_retina( cortex_map[ui][uj].centerx+0.5, cortex_map[ui][uj].centery+0.5,
01229 0.5, left_offset);
01230
01231 ipc_notify(IPC_ALL,IPC_VERBOSE,"ppm_afferent_weights: Values ranged from %g to %g",
01232 min_value,max_value);
01233
01234 return width;
01235 }
01236
01237
01238
01244 LOff ppm_draw_angle_histogram( OrientationHistogram histo, int symmetric, int left_offset)
01245 {
01246 const int width = ppm_init_histogram_plot(symmetric,left_offset);
01247 const double bound = ppm_histo_percentage_range*(symmetric? 0.5 : 1);
01248 double max_value=0;
01249 double min_value=0;
01250 int j;
01251
01252 if (width)
01253 for( j=0; j < or_num_angles; j++) {
01254 const double value = ( (histo.total_level==0) ? 0 : histo.levels[j]/histo.total_level);
01255 draw_histogram_bin(value, j, False, symmetric, left_offset);
01256 if (value > max_value) max_value = value;
01257 if (value < min_value) min_value = value;
01258 }
01259
01260 if (max_value*100.0 > bound)
01261 ipc_notify(IPC_ALL,IPC_CAUTION,"ppm_draw_angle_histogram: cropped maximum level of %g%% at %g%%",
01262 max_value*100.0,bound);
01263
01264 if (symmetric && min_value*100.0 < -bound)
01265 ipc_notify(IPC_ALL,IPC_CAUTION,"ppm_draw_angle_histogram: cropped minimum level of %g%% at %g%%",
01266 min_value*100.0,-bound);
01267
01268 return width;
01269 }
01270
01271
01272
01273 LOff ppm_draw_angle_histogram_difference( OrientationHistogram poshisto,
01274 OrientationHistogram neghisto,
01275 int left_offset)
01276 {
01277 int j;
01278 OrientationHistogram histo;
01279
01280
01281 histo.total_level = 0;
01282 for( j=0; j < or_num_angles; j++) {
01283 histo.levels[j] = poshisto.levels[j] - neghisto.levels[j];
01284 histo.total_level += poshisto.levels[j] + neghisto.levels[j];
01285 }
01286
01287 return ppm_draw_angle_histogram( histo, True, left_offset);
01288 }
01289
01290
01291
01292 LOff ppm_draw_or_color_key(int num_examples, int key_length, int vertical, int left_offset)
01293 {
01294 const int bar_spacing = key_length/(num_examples-1);
01295 const double bar_length = MAX(2,0.9*bar_spacing);
01296 const double bar_thick = MAX(1,bar_length/4.6);
01297
01298 const int width = (vertical? bar_spacing : key_length+bar_spacing);
01299 const int center = (vertical? left_offset+width/2 : ppm_border+ppm_height/2);
01300 const int offset = (vertical? (ppm_height-key_length)/2 : left_offset+bar_spacing/2);
01301
01302 int i;
01303
01304 if (!canExtendWidthTo(width))
01305 return 0;
01306
01307 for(i=0; i<num_examples; i++) {
01308
01309 const int iprime = (num_examples-1-i);
01310 XColor color;
01311 hsv2rgb(iprime*1.0/(num_examples-1), 1.0, 1.0, &color);
01312
01313 ppm_draw_line_at_angle(vertical? center : offset+i*bar_spacing,
01314 vertical? offset+i*bar_spacing : center,
01315 (iprime*M_PI)/(num_examples-1),
01316 bar_length, bar_thick, color);
01317 }
01318
01319 return width;
01320 }
01321
01322
01323
01324
01325
01326
01327
01328
01329
01330
01331
01332
01335 LOff ppm_draw_presentation(double input_v[RNMAX*RNMAX*MAX_NUM_EYES],
01336 double init[NMAX][NMAX],
01337 double settled[NMAX][NMAX])
01338 {
01339 int left_offset = ppm_border;
01340 OrientationHistogram poshisto;
01341 OrientationHistogram neghisto;
01342
01343 left_offset += ppm_draw_retina(0, input_v, left_offset) + ppm_border;
01344
01345 left_offset += ppm_draw_activity( init, left_offset) + ppm_border;
01346 if (ppm_histograms && or_dumped != Uninitialized &&
01347 !compute_orientation_distribution(ppm_start_i, ppm_end_i-1,
01348 ppm_start_j, ppm_end_j-1,
01349 &neghisto, init,combined_eyes))
01350 left_offset += ppm_draw_angle_histogram( neghisto, False, left_offset) + ppm_border;
01351
01352 left_offset += ppm_draw_activity( settled, left_offset) + ppm_border;
01353 if (ppm_histograms && or_dumped != Uninitialized &&
01354 !compute_orientation_distribution(ppm_start_i, ppm_end_i-1,
01355 ppm_start_j, ppm_end_j-1,
01356 &poshisto, settled,combined_eyes))
01357 left_offset += ppm_draw_angle_histogram( poshisto, False, left_offset) + ppm_border;
01358
01359
01360 01361
01362
01363 {
01364 int eye;
01365 for (eye=1; eye<num_eyes; eye++)
01366 left_offset += ppm_draw_retina(eye,&input_v[INP_INDEX(eye,0,0)], left_offset) + ppm_border;
01367 }
01368
01369
01370 if ((ppm_color_keys==Uninitialized && or_dumped != Uninitialized &&
01371 (ppm_histograms ||
01372 ppm_retina_subplot==PPM_ORIENTATION ||
01373 ppm_activity_subplot==PPM_ORIENTATION)) ||
01374 ppm_color_keys == True)
01375 left_offset += ppm_draw_or_color_key(ppm_color_key_num, ppm_height-4*ppm_border, True, left_offset)
01376 + ppm_border;
01377
01378 return left_offset;
01379 }
01380
01381
01382
01384 LOff ppm_draw_orientations(int or_preferences[EYE_ARRAY_SIZE][NMAX][NMAX],
01385 double or_selectivities[EYE_ARRAY_SIZE][NMAX][NMAX],
01386 bool selectivity_only)
01387 {
01388 int left_offset = ppm_border;
01389 int offset=0;
01390 int eye;
01391
01392 for (eye=0; eye<=combined_eyes; eye++) {
01393
01394
01395 if (ppm_shaded_plots)
01396 offset = ppm_draw_or_pref( or_preferences[eye], or_selectivities[eye], selectivity_only, left_offset) + ppm_border;
01397
01398 if (ppm_line_plots)
01399 offset = ppm_draw_or_pref_line(or_preferences[eye], or_selectivities[eye], left_offset) + ppm_border;
01400
01401
01402 if ((ppm_ui != Uninitialized) && (ppm_uj != Uninitialized)) {
01403
01404 if (ppm_outline_weights)
01405 draw_box_outline_on_cortex( ppm_ui+0.5, ppm_uj+0.5, 0.5, left_offset);
01406
01407 draw_outline_on_cortex(ppm_ui,ppm_uj,inh_rad,left_offset,inhWeightAbove);
01408
01409
01410 ipc_notify(IPC_ALL,IPC_VERBOSE,"ppm_draw: Neuron (%d,%d) had an orientation preference of %f degrees and selectivity of %f",
01411 ppm_ui,ppm_uj,
01412 (double)OR_PREF_TO_DEGREES(or_preferences[eye][ppm_ui][ppm_uj]),
01413 (double)or_selectivities[eye][ppm_ui][ppm_uj]);
01414 }
01415
01416 left_offset += offset;
01417
01418 if (ppm_histograms && !selectivity_only && (or_dumped != Uninitialized)) {
01419 OrientationHistogram histo;
01420 if (!compute_orientation_distribution(ppm_start_i, ppm_end_i-1,
01421 ppm_start_j, ppm_end_j-1,
01422 &histo, NULL,eye))
01423 left_offset += ppm_draw_angle_histogram(histo, False, left_offset) + ppm_border;
01424 }
01425 }
01426
01427 if ((!selectivity_only && ppm_color_keys==Uninitialized && ppm_shaded_plots) ||
01428 (ppm_color_keys!=Uninitialized && ppm_color_keys))
01429 left_offset += ppm_draw_or_color_key(ppm_color_key_num, ppm_height-4*ppm_border, True, left_offset)
01430 + ppm_border;
01431
01432 return left_offset;
01433 }
01434
01435
01436
01438 LOff ppm_draw_ocular_dominance(double od_pref_array[NMAX][NMAX])
01439 {
01440 int left_offset = ppm_border;
01441 int offset=0;
01442
01443 offset = ppm_draw_od_pref(od_pref_array, left_offset) + ppm_border;
01444
01445
01446 if ((ppm_ui != Uninitialized) && (ppm_uj != Uninitialized)) {
01447
01448 if (ppm_outline_weights)
01449 draw_box_outline_on_cortex( ppm_ui+0.5, ppm_uj+0.5, 0.5, left_offset);
01450
01451 draw_outline_on_cortex(ppm_ui,ppm_uj, inh_rad, left_offset, inhWeightAbove);
01452
01453
01454 ipc_notify(IPC_ALL,IPC_VERBOSE,
01455 "ppm_draw: Neuron (%d,%d) had an ocular dominance preference of %f",
01456 ppm_ui,ppm_uj,(double)(od_pref_array[ppm_ui][ppm_uj]));
01457 }
01458
01459 left_offset += offset;
01460
01461 return left_offset;
01462 }
01463
01464
01465
01471 LOff ppm_draw_weights(int ui, int uj )
01472 {
01473 int left_offset = ppm_border;
01474 int eye;
01475 OrientationHistogram histo;
01476
01477
01478 left_offset += ppm_border +
01479 ppm_draw_afferent_weights(cortex_map[ui][uj].centerx,
01480 cortex_map[ui][uj].centery,
01481 cortex_map[ui][uj].weights[0],
01482 ui, uj, left_offset);
01483
01484
01485 left_offset += ppm_border +
01486 ppm_draw_lateral_weights(ui,uj, cortex_map[ui][uj].lat_exc_wts,
01487 exc_rad,exc_array_width,left_offset,
01488 False,ppm_always_mark_neuron);
01489
01490 if (ppm_histograms && or_dumped != Uninitialized &&
01491 !compute_weight_distribution(&histo,ui,uj, cortex_map[ui][uj].lat_exc_wts,
01492 exc_rad, exc_array_width, combined_eyes))
01493 left_offset += ppm_draw_angle_histogram( histo, False, left_offset) + ppm_border;
01494
01495
01496 left_offset += ppm_border +
01497 ppm_draw_lateral_weights(ui,uj, cortex_map[ui][uj].lat_inh_wts,
01498 inh_rad, inh_array_width, left_offset,
01499 True,True);
01500
01501 if (ppm_histograms && or_dumped != Uninitialized &&
01502 !compute_weight_distribution(&histo, ui,uj, cortex_map[ui][uj].lat_inh_wts,
01503 inh_rad, inh_array_width, combined_eyes))
01504 left_offset += ppm_draw_angle_histogram(histo, False, left_offset) + ppm_border;
01505
01506
01507 for (eye=1; eye<num_eyes; eye++)
01508 left_offset += ppm_border +
01509 ppm_draw_afferent_weights(cortex_map[ui][uj].centerx,
01510 cortex_map[ui][uj].centery,
01511 cortex_map[ui][uj].weights[eye],
01512 ui, uj, left_offset);
01513
01514 if ((ppm_color_keys==Uninitialized && or_dumped != Uninitialized &&
01515 (ppm_histograms ||
01516 ppm_afferent_subplot==PPM_ORIENTATION ||
01517 ppm_lateral_subplot==PPM_ORIENTATION)) ||
01518 ppm_color_keys == True)
01519 left_offset += ppm_draw_or_color_key(ppm_color_key_num, ppm_height-4*ppm_border, True, left_offset)
01520 + ppm_border;
01521
01522 return left_offset;
01523 }
01524
01525
01526
01533 void ppm_draw_afferent_weight_map(const char* filename, int eye, int baseline_eye)
01534 {
01535 const int cursorincrement = rf_radius*2+1+ppm_interior_border;
01536 const int dx = (ppm_end_i-ppm_start_i);
01537 const int dy = (ppm_end_j-ppm_start_j);
01538 const int image_width = ppm_border+cursorincrement*(1+(dx-1)/ppm_neuron_skip_aff)+ppm_border;
01539 const int image_height = ppm_border+cursorincrement*(1+(dy-1)/ppm_neuron_skip_aff)+ppm_border;
01540 XColor interior = ppm_interior_outline ? ppm_background_color : ppm_foreground_color;
01541 interior.flags = 0;
01542
01543 vector< vector<XColor> > image_data(image_width,vector<XColor>(image_height,ppm_background_color));
01544
01545 int cursorx = ppm_border;
01546 int cursory = ppm_border;
01547 for (int uj=ppm_start_j; uj<ppm_end_j; uj += ppm_neuron_skip_aff) {
01548 for (int ui=ppm_start_i; ui<ppm_end_i; ui += ppm_neuron_skip_aff) {
01549 const int center_x = cortex_map[ui][uj].centerx;
01550 const int center_y = cortex_map[ui][uj].centery;
01551 const int lowx = MAX(center_x-rf_radius,0 );
01552 const int highx = MIN(center_x+rf_radius,RN-1);
01553 const int lowy = MAX(center_y-rf_radius,0 );
01554 const int highy = MIN(center_y+rf_radius,RN-1);
01555
01556 double scale_factor;
01557 double scale_offset;
01558 compute_weight_scale(center_x,center_y,RN,circular_aff_wts,
01559 rf_radius,rf_radius*2+1,
01560 cortex_map[ui][uj].weights[eye],
01561 False, &scale_factor, &scale_offset);
01562
01563
01564 for(int x=center_x-rf_radius; x<=center_x+rf_radius+ppm_interior_border; x++)
01565 for(int y=center_y-rf_radius; y<=center_y+rf_radius+ppm_interior_border; y++) {
01566 const double level = ((x<lowx || x>highx || y<lowy || y>highy) ? 0
01567 : MAX(0,cortex_map[ui][uj].weights[eye][x-lowx][y-lowy]));
01568 const double diff = ((baseline_eye==Uninitialized ||
01569 (x<lowx || x>highx || y<lowy || y>highy)) ? level
01570 : level - MAX(0,cortex_map[ui][uj].weights[baseline_eye][x-lowx][y-lowy]));
01571 const double value = (diff < ppm_weight_threshold ? 0 :
01572 (diff+scale_offset)*scale_factor);
01573 const XColor color = ((x>center_x+rf_radius || y>center_y+rf_radius) ? interior
01574 : ppm_lookup_color(ui,uj,value,ppm_afferent_subplot));
01575 image_data[x-center_x+rf_radius+cursorx][y-center_y+rf_radius+cursory] = color;
01576 }
01577 cursorx += cursorincrement;
01578 }
01579 cursorx = ppm_border;
01580 cursory += cursorincrement;
01581 }
01582
01583 ppm_write_image_to_file( image_data,filename,filename,image_width,image_height,255 );
01584 }
01585
01586
01587
01588
01589
01590
01591
01592
01594 void compute_weight_scale( int ui, int uj, int max_coord, int circular_wts,
01595 int radius, int ar_width,
01596 void* weights, int weights_are_lat,
01597 double* factor, double* offset )
01598 {
01599 const int type = ppm_weight_scale_type;
01600
01601
01602 *factor=1.0;
01603 *offset=0.0;
01604
01605
01606 if (type == PPM_WTSCALE_FIXED)
01607 *factor=ppm_afferent_multiplier;
01608
01609
01610 else {
01611 const int array_width = (weights_are_lat && type == PPM_WTSCALE_INHIB ?
01612 inh_array_width : ar_width);
01613 const int rad = (ppm_weight_scale_init_count ? (array_width-1)/2 : radius);
01614 const double radius_sq = (rad+circular_radius_trim)*(rad+circular_radius_trim);
01615
01616 const int lowi = (ppm_weight_scale_max_count ? ui-rad : MAX(ui-rad, 0));
01617 const int highi = (ppm_weight_scale_max_count ? ui+rad : MIN(ui+rad,max_coord));
01618 const int lowj = (ppm_weight_scale_max_count ? uj-rad : MAX(uj-rad, 0));
01619 const int highj = (ppm_weight_scale_max_count ? uj+rad : MIN(uj+rad,max_coord));
01620
01621 const int scale_with_values = (type == PPM_WTSCALE_ACTIVE ||
01622 type == PPM_WTSCALE_RELATIVE ||
01623 type == PPM_WTSCALE_PEAKRELATIVE );
01624
01625 double max = 0.0;
01626 double min = 1.0;
01627 int count = 0;
01628 int active= 0;
01629 double value = 0.0;
01630 int i,j;
01631
01632 typedef a_weight a_weights[WTMAX];
01633
01634 for( i=lowi; i <= highi; i++)
01635 for(j=lowj; j <= highj; j++) {
01636 if (scale_with_values) {
01637 if (weights_are_lat)
01638 value = ((l_weight*)weights)[LAT_INDEX(ui,uj,i,j,rad,ar_width)];
01639 else
01640 value = ((a_weights*)weights)[i-lowi][j-lowj];
01641
01642 if (value > ppm_weight_threshold) {
01643 active++;
01644 if (value > max) max = value;
01645 if (value < min) min = value;
01646 }
01647 }
01648 else if (circular_wts)
01649 count += (WITHIN_RADIUS(i-ui,j-uj,radius_sq)? 1 : 0);
01650 else
01651 count++;
01652 }
01653
01654 if (type == PPM_WTSCALE_RELATIVE) {
01655 *factor= ((max-min)>0 ? 1.0/(max-min) : 1.0);
01656 *offset= -min;
01657 }
01658
01659 else if (type == PPM_WTSCALE_PEAKRELATIVE)
01660 *factor = (max>0 ? 1.0/max : 1.0);
01661
01662 else if (type == PPM_WTSCALE_ACTIVE)
01663 *factor = 1.0*active;
01664
01665 else
01666 *factor = 1.0*count;
01667 }
01668 }
01669
01670
01671
01672 int ppm_scaled_cortex_unit_pixels( void ) { return (int)ppm_cortex_scale; }
01673 int ppm_scaled_cortex_plot_height( void ) { return ppm_scaled_cortex_unit_pixels()*(ppm_end_j-ppm_start_j); }
01674 int ppm_scaled_cortex_plot_width( void ) { return ppm_scaled_cortex_unit_pixels()*(ppm_end_i-ppm_start_i); }
01675 int ppm_scaled_cortex_height_offset(void) { return (ppm_height - ppm_scaled_cortex_plot_height())/2; }
01676
01677 int ppm_scaled_retina_unit_pixels( void ) { return (int)ppm_retina_scale; }
01678 int ppm_scaled_retina_plot_height( void ) { return ppm_scaled_retina_unit_pixels()*(ppm_end_y-ppm_start_y); }
01679 int ppm_scaled_retina_plot_width( void ) { return ppm_scaled_retina_unit_pixels()*(ppm_end_x-ppm_start_x); }
01680 int ppm_scaled_retina_height_offset(void) { return (ppm_height - ppm_scaled_retina_plot_height())/2; }
01681
01682
01683 int ppm_scaled_histogram_bin_pixels( int num_bins )
01684 { return (int)(ppm_scaled_cortex_plot_height()/num_bins); }
01685
01686 int ppm_scaled_histogram_plot_height(int num_bins )
01687 { return ppm_scaled_histogram_bin_pixels(num_bins)*num_bins; }
01688
01689 int ppm_scaled_histogram_plot_width( int num_bins, double scale )
01690 { return (int)(ppm_scaled_histogram_plot_height(num_bins)*scale); }
01691
01692 int ppm_scaled_histogram_height_offset(int num_bins )
01693 { return (ppm_height - ppm_scaled_histogram_plot_height(num_bins))/2; }
01694
01695
01696
01702 XColor ppm_get_drawing_color(int lowi, int highi, int lowj, int highj, XColor set_color)
01703 {
01704
01705 if ((set_color.flags & BadPixel) != 0) {
01706
01707 double value, dummy;
01708 double total = 0;
01709 double average;
01710 int midi=lowi+(highi-lowi)/2;
01711 int midj=lowj+(highj-lowj)/2;
01712
01713 rgb2hsv(image[lowi ][midj ], &dummy, &dummy, &value); total += value;
01714 rgb2hsv(image[midi ][lowj ], &dummy, &dummy, &value); total += value;
01715 rgb2hsv(image[midi ][highj], &dummy, &dummy, &value); total += value;
01716 rgb2hsv(image[highi][midj ], &dummy, &dummy, &value); total += value;
01717 average=total/4;
01718
01719 01720
01721
01722 if (average >= 0.75)
01723 return Black;
01724
01725 else if (average < 0.25)
01726 return White;
01727
01728 else
01729 return Blue;
01730 }
01731
01732 return set_color;
01733 }
01734
01735
01736
01737 void ppm_clear_image(int bg_R, int bg_G, int bg_B)
01738 {
01739 int i, j;
01740
01741 for (i=0; i<IMG_SIZE_X; i++)
01742 for (j=0; j<IMG_SIZE_Y; j++){
01743 image[i][j].red = bg_R;
01744 image[i][j].green = bg_G;
01745 image[i][j].blue = bg_B;
01746 }
01747 }
01748
01749
01750
01755 void create_colormap_RGB( XColor colormap[HIGHEST_COLOR_LEVEL+1], int numcolors )
01756 {
01757
01758 const int rangeby3 = (int)(numcolors/3);
01759 const double multiplier = HIGHEST_COLOR_LEVEL/(double)rangeby3;
01760
01761 int i;
01762
01763 for(i= 0; i< numcolors; i++ ) {
01764 colormap[i].green = 0;
01765 colormap[i].blue = 0;
01766 if ( i < rangeby3 )
01767 colormap[i].red = (int)floor((double)i * multiplier);
01768 else{
01769 colormap[i].red = HIGHEST_COLOR_LEVEL;
01770 if ( i < 2*rangeby3)
01771 colormap[i].green = (int)floor((double)(i-rangeby3) * multiplier);
01772 else{
01773 colormap[i].green = HIGHEST_COLOR_LEVEL;
01774 colormap[i].blue = (int)floor((double)(i-2*rangeby3)*multiplier);
01775 }
01776 }
01777 }
01778 }
01779
01780
01781
01788 void hsv2rgb(
01789 double h, double s, double v,
01790 XColor *c
01791 )
01792 {
01793 int j;
01794 double rd, gd, bd;
01795 double f, p, q, T;
01796 double hue;
01797
01798
01799 #ifndef FOLEY_STANDARD_COLORS
01800 h=1-h;
01801 #endif
01802
01803
01804 if (h==NOHUE || s==0.0) { rd = v; gd = v; bd = v; }
01805 else {
01806
01807 if (s>1.0) s = 1.0; if (s<0.0) s = 0.0;
01808 if (v>1.0) v = 1.0; if (v<0.0) v = 0.0;
01809
01810 if (h >= 1.0 || h < 0.0) hue = 0.0;
01811 else hue = h * 6.0;
01812
01813 j = (int) floor(hue);
01814 if (j<0) j=0;
01815 f = hue - j;
01816 p = v * (1-s);
01817 q = v * (1 - (s*f));
01818 T = v * (1 - (s*(1 - f)));
01819
01820 switch (j) {
01821 case 0: rd = v; gd = T; bd = p; break;
01822 case 1: rd = q; gd = v; bd = p; break;
01823 case 2: rd = p; gd = v; bd = T; break;
01824 case 3: rd = p; gd = q; bd = v; break;
01825 case 4: rd = T; gd = p; bd = v; break;
01826 case 5: rd = v; gd = p; bd = q; break;
01827 default: rd = v; gd = T; bd = p; break;
01828 }
01829 }
01830
01831 c->red = (RGB_value)floor((rd * HIGHEST_COLOR_LEVEL) + 0.5);
01832 c->green = (RGB_value)floor((gd * HIGHEST_COLOR_LEVEL) + 0.5);
01833 c->blue = (RGB_value)floor((bd * HIGHEST_COLOR_LEVEL) + 0.5);
01834 c->flags = 0;
01835 }
01836
01837
01838 01839 01840 01841
01842 void rgb2hsv(XColor c,
01843 double *h,
01844 double *s,
01845 double *v
01846 )
01847 {
01848 double r = c.red / (1.0*(HIGHEST_COLOR_LEVEL+1));
01849 double g = c.green / (1.0*(HIGHEST_COLOR_LEVEL+1));
01850 double b = c.blue / (1.0*(HIGHEST_COLOR_LEVEL+1));
01851
01852
01853 double max = MAX(MAX(r,g),b);
01854 double min = MIN(MIN(r,g),b);
01855
01856
01857 *v = max;
01858
01859
01860 *s = (max == 0.0) ? 0.0 : ((max-min)/max);
01861
01862
01863 if (*s == 0.0)
01864 *h = NOHUE;
01865 else {
01866 double delt = max - min;
01867
01868 if (r == max)
01869 *h = (g - b)/delt;
01870
01871 else if (g == max)
01872 *h = 2.0 + (b - r)/delt;
01873
01874 else if (b == max)
01875 *h = 4.0 + (r - g)/delt;
01876
01877
01878
01879
01880
01881 *h *= (60.0/360.0); if (*h < 0.0) *h += 1.0;
01882 }
01883 }
01884
01885
01888 void ppm_write_header( FILE *file, const char *comments, int width, int height, int max_val )
01889 {
01890 fprintf(file, "P6\n");
01891 fprintf(file, "#%s\n", comments);
01892 fprintf(file, "%d %d\n", width, height);
01893 fprintf(file, "%d\n", max_val);
01894 }
01895
01896
01897
01898 int ppm_write_pixel( FILE *file, XColor pixel, int max_val )
01899 {
01900 char rgb_value[3];
01901 rgb_value[0]=(char)((max_val/(double)(HIGHEST_COLOR_LEVEL+1))*(double)pixel.red);
01902 rgb_value[1]=(char)((max_val/(double)(HIGHEST_COLOR_LEVEL+1))*(double)pixel.green);
01903 rgb_value[2]=(char)((max_val/(double)(HIGHEST_COLOR_LEVEL+1))*(double)pixel.blue);
01904
01905 if (3 != fwrite(&rgb_value, sizeof(rgb_value[0]), 3, file)) {
01906 ipc_notify(IPC_ALL,IPC_ERROR,"Cannot write to pixmap file");
01907 return -1;
01908 }
01909
01910 return 0;
01911 }
01912
01913
01914
01916 int ppm_write_to_file( const char* filename, const char *comments, int width, int height, int max_val )
01917 { return ppm_write_image_to_file( image, filename, comments, width, height, max_val ); }
01918
01919
01920
01922 template<class T>
01923 int ppm_write_image_to_file( T imagedata, const char* filename, const char *comments, int width, int height, int max_val )
01924 {
01925 int i, j;
01926 FILE *file;
01927
01928 if ((file=fopen(filename,"w+"))==NULL){
01929 ipc_notify(IPC_ALL,IPC_ERROR,"Could not open output file %s", filename);
01930 return -1;
01931 }
01932
01933 ppm_write_header( file, comments, width, height, max_val);
01934
01935 for (j=0; j<height; j++)
01936 for (i=0; i<width; i++)
01937 if (ppm_write_pixel(file, imagedata[i][j], max_val))
01938 return -2;
01939 fclose(file);
01940
01941 if ((ppm_spawn_viewer==Uninitialized && interactive)
01942 || (ppm_spawn_viewer!=Uninitialized && ppm_spawn_viewer) ) {
01943 static int spawned_already=False;
01944 if (!spawned_already || ppm_spawn_independent_viewers) {
01945 char cmdtxt[MAXFILENAMELENGTH*2];
01946 snprintf(cmdtxt,MAXFILENAMELENGTH*2,"%s %s %s",
01947 (running_remotely? ppm_remote_viewer : ppm_image_viewer),
01948 filename,
01949 (running_remotely? "" : "&"));
01950 system(cmdtxt);
01951 spawned_already=True;
01952 }
01953 }
01954
01955 return 0;
01956 }
01957
01958
01959
01961 XColor ppm_lookup_color( int i, int j, double scaled_level, int subplot, int paper_based)
01962 {
01963 XColor color;
01964 const int assume_paper = paper_based==Uninitialized ? ppm_paper_based_colors : paper_based;
01965
01966 scaled_level = CROP(0.0,1.0,scaled_level);
01967
01968
01969 if (assume_paper)
01970
01971 switch(subplot) {
01972
01973
01974 case PPM_RYW: color = colors[(int)( (1-scaled_level) * (double)(ncolors-1) )]; break;
01975
01976
01977 case PPM_GRAYSCALE: hsv2rgb(NOHUE, 0.0, 1-scaled_level, &color); break;
01978
01979
01980 case PPM_ORIENTATION:
01981
01982 if (or_dumped != Uninitialized) {
01983 double hue = OR_PREF_TO_DEGREES(or_pref[combined_eyes][i][j])/180;
01984 double value = 1.0;
01985 double scaled_select = CROP(0.0,1.0,or_select[combined_eyes][i][j]*ppm_selectivity_multiplier);
01986
01987 switch (ppm_orientation_subplot) {
01988 case PPM_SELECTIVITY:
01989 value = MAX(1-scaled_level, scaled_select);
01990 break;
01991 case PPM_NONE:
01992 break;
01993 }
01994 hsv2rgb(hue,scaled_level,value, &color);
01995 }
01996 else
01997 hsv2rgb(NOHUE, 0.0, 1-scaled_level, &color);
01998 break;
01999
02000
02001 case PPM_OCULARDOMINANCE: hsv2rgb(od_pref[i][j]/6, scaled_level, 1.0, &color); break;
02002
02003 case PPM_SINGLEHUE: hsv2rgb(ppm_subplot_hue, scaled_level, 1.0, &color); break;
02004
02005 default:
02006 ipc_notify(IPC_ONE,IPC_WARNING,"Unsupported subplot: %d",subplot);
02007 }
02008
02009
02010 else
02011 switch(subplot) {
02012
02013
02014 case PPM_RYW: color = colors[(int)( scaled_level * (double)(ncolors-1) )]; break;
02015
02016
02017 case PPM_GRAYSCALE: hsv2rgb(NOHUE, 0.0, scaled_level, &color); break;
02018
02019
02020 case PPM_ORIENTATION:
02021
02022 if (or_dumped != Uninitialized) {
02023 double hue = OR_PREF_TO_DEGREES(or_pref[combined_eyes][i][j])/180;
02024 double saturation = 1.0;
02025 double scaled_select = CROP(0.0,1.0,or_select[combined_eyes][i][j]*ppm_selectivity_multiplier);
02026
02027 switch (ppm_orientation_subplot) {
02028 case PPM_SELECTIVITY:
02029 saturation = scaled_select;
02030 break;
02031 case PPM_NONE:
02032 break;
02033 }
02034 hsv2rgb(hue,saturation,scaled_level, &color);
02035 }
02036
02037 else hsv2rgb(NOHUE, 0.0, scaled_level, &color);
02038 break;
02039
02040
02041 case PPM_OCULARDOMINANCE: hsv2rgb(od_pref[i][j]/6, 1.0, scaled_level, &color); break;
02042
02043 case PPM_SINGLEHUE: hsv2rgb(ppm_subplot_hue, 1.0, scaled_level, &color); break;
02044
02045 default:
02046 ipc_notify(IPC_ONE,IPC_WARNING,"Unsupported subplot: %d",subplot);
02047 }
02048
02049 return color;
02050 }
02051
02052
02053
02055 int canExtendWidthTo(int width)
02056 {
02057 if (width > IMG_SIZE_X) {
02058 ipc_notify(IPC_ALL,IPC_ERROR,"ppm_draw: Width %d is too large for image of %d; aborting",
02059 width, (int)IMG_SIZE_X);
02060 return 0;
02061 }
02062 else return 1;
02063 }
02064
02065
02066
02068 int ppm_init_retina_plot(int left_offset)
02069 {
02070 const int width = ppm_scaled_retina_plot_width();
02071
02072 if (!canExtendWidthTo(left_offset + width))
02073 return 0;
02074
02075 draw_retina_unit(Black,0,0,True,left_offset);
02076
02077 return width;
02078 }
02079
02080
02081
02083 int ppm_init_cortex_plot(int left_offset)
02084 {
02085 const int width = ppm_scaled_cortex_plot_width();
02086
02087 if (!canExtendWidthTo(left_offset + width))
02088 return 0;
02089
02090 draw_cortex_unit(Black,0,0,True,left_offset);
02091
02092 return width;
02093 }
02094
02095
02096
02098 int ppm_init_histogram_plot(int symmetric, int left_offset)
02099 {
02100 const int width = ppm_scaled_histogram_plot_width(or_num_angles,ppm_histo_scale_factor);
02101
02102 if (!canExtendWidthTo(left_offset + width))
02103 return 0;
02104
02105 draw_histogram_bin((symmetric? -1 : 0),0,True,False,left_offset);
02106
02107 return width;
02108 }
02109
02110
02111
02112
02113
02114
02115
02116
02117 void draw_rectangle( XColor color,
02118 int upper_left_x, int upper_left_y,
02119 int x_pixels, int y_pixels )
02120 {
02121 int x,y;
02122
02123 for(x=upper_left_x; x < upper_left_x+x_pixels; x++)
02124 for (y=upper_left_y; y <upper_left_y+y_pixels; y++)
02125 ppm_draw_pixel(x,y,color);
02126 }
02127
02128
02129
02130 void draw_horizontal_line( XColor color, int l_i, int h_i, int j )
02131 {
02132 int i;
02133 for( i=l_i; i <= h_i; i++)
02134 ppm_draw_pixel(i,j,color);
02135 }
02136
02137
02138 void draw_vertical_line( XColor color, int i, int l_j, int h_j )
02139 {
02140 int j;
02141 for( j=l_j; j <= h_j; j++)
02142 ppm_draw_pixel(i,j,color);
02143 }
02144
02145
02146
02151 int draw_box_outline( XColor color, int xl, int xh, int yl, int yh, int width )
02152 {
02153 int p;
02154
02155 for (p = 0; p < width ; p++) {
02156 draw_vertical_line( color, xl-p, yl-p, yh+p);
02157 draw_vertical_line( color, xh+p, yl-p, yh+p);
02158 draw_horizontal_line(color, xl-p, xh+p, yl-p);
02159 draw_horizontal_line(color, xl-p, xh+p, yh+p);
02160 }
02161
02162 return 0;
02163 }
02164
02165
02166
02172 int draw_box_outline_on_retina( double centeri, double centerj, double radius, int left_offset)
02173 {
02174 const int npixels_perunit = ppm_scaled_retina_unit_pixels();
02175 const int height_offset = ppm_scaled_retina_height_offset();
02176
02177 const double lowi = MAX(centeri-radius,ppm_start_x);
02178 const double highi = MIN(centeri+radius,ppm_end_x );
02179 const double lowj = MAX(centerj-radius,ppm_start_y);
02180 const double highj = MIN(centerj+radius,ppm_end_y );
02181
02182 const int xl = left_offset + (int)((lowi -ppm_start_x) * npixels_perunit) -1;
02183 const int xh = left_offset + (int)((highi-ppm_start_x) * npixels_perunit) ;
02184 const int yl = height_offset + (int)((lowj -ppm_start_y) * npixels_perunit) -1;
02185 const int yh = height_offset + (int)((highj-ppm_start_y) * npixels_perunit) ;
02186
02187
02188 XColor color;
02189 color = ppm_get_drawing_color(xl+1, xh-1, yl+1, yh-1, ppm_foreground_color );
02190
02191 draw_box_outline(color,xl,xh,yl,yh,ppm_outline_width);
02192
02193 return ppm_scaled_retina_plot_width();
02194 }
02195
02196
02197
02203 int draw_box_outline_on_cortex( double centeri, double centerj, double radius, int left_offset)
02204 {
02205 const int npixels_perunit = ppm_scaled_cortex_unit_pixels();
02206 const int height_offset = ppm_scaled_cortex_height_offset();
02207
02208 const double lowi = MAX(centeri-radius,ppm_start_i);
02209 const double highi = MIN(centeri+radius,ppm_end_i);
02210 const double lowj = MAX(centerj-radius,ppm_start_j);
02211 const double highj = MIN(centerj+radius,ppm_end_j);
02212
02213 const int xl = left_offset + (int)((lowi -ppm_start_i) * npixels_perunit) -1;
02214 const int xh = left_offset + (int)((highi-ppm_start_i) * npixels_perunit) ;
02215 const int yl = height_offset + (int)((lowj -ppm_start_j) * npixels_perunit) -1;
02216 const int yh = height_offset + (int)((highj-ppm_start_j) * npixels_perunit) ;
02217
02218
02219 XColor color;
02220 color = ppm_get_drawing_color(xl+1, xh-1, yl+1, yh-1, ppm_foreground_color );
02221
02222 draw_box_outline(color,xl,xh,yl,yh,ppm_outline_width);
02223
02224 return ppm_scaled_cortex_plot_width();
02225 }
02226
02227
02228
02229 void draw_retina_unit( XColor color, int x, int y, int reset_values, int left_offset)
02230 {
02231 static int npixels_perunit=0,height_offset=0;
02232
02233 if (reset_values) {
02234 npixels_perunit = ppm_scaled_retina_unit_pixels();
02235 height_offset = ppm_scaled_retina_height_offset();
02236 }
02237 else {
02238 const int square_left_offset = left_offset + (x-ppm_start_x)*npixels_perunit;
02239 const int square_height_offset = height_offset + (y-ppm_start_y)*npixels_perunit;
02240
02241 draw_rectangle (color, square_left_offset, square_height_offset,
02242 npixels_perunit, npixels_perunit);
02243 }
02244 }
02245
02246
02247
02248 void draw_cortex_unit( XColor color, int i, int j, int reset_values, int left_offset)
02249 {
02250 static int npixels_perunit=0,height_offset=0;
02251
02252 if (reset_values) {
02253 npixels_perunit = ppm_scaled_cortex_unit_pixels();
02254 height_offset = ppm_scaled_cortex_height_offset();
02255 }
02256 else {
02257 const int square_left_offset = left_offset + (i-ppm_start_i)*npixels_perunit;
02258 const int square_height_offset = height_offset + (j-ppm_start_j)*npixels_perunit;
02259
02260 draw_rectangle (color, square_left_offset, square_height_offset,
02261 npixels_perunit, npixels_perunit);
02262 }
02263 }
02264
02265
02266
02267 void draw_histogram_bin( double value, int j, int reset_values, int draw_zero, int left_offset)
02268 {
02269 static int npixels_perunit=0,scaled_height=0,scaled_width=0,zero_pixel=0,bin_width=0,height_offset=0;
02270 static double val_scale=0;
02271 static XColor bg,fg,color;
02272
02273 if (reset_values) {
02274 npixels_perunit = ppm_scaled_histogram_bin_pixels(or_num_angles);
02275 scaled_height = ppm_scaled_histogram_plot_height(or_num_angles);
02276 scaled_width = ppm_scaled_histogram_plot_width(or_num_angles,ppm_histo_scale_factor);
02277 height_offset = ppm_scaled_histogram_height_offset(or_num_angles);
02278 zero_pixel = (value < 0 ? left_offset+scaled_width/2 : left_offset);
02279 bin_width = (value < 0 ? scaled_width/2+1 : scaled_width);
02280 val_scale = scaled_width*100/ppm_histo_percentage_range;
02281 bg = (ppm_paper_based_colors ? White : Black);
02282 fg = (ppm_paper_based_colors ? Black : White);
02283
02284 if (scaled_height < or_num_angles)
02285 ipc_notify(IPC_ONE,IPC_WARNING,"Cortex plot height is insufficient to show angle histogram (%d < %d)",
02286 scaled_height,or_num_angles);
02287 }
02288 else {
02289
02290 const int square_height_offset = height_offset + (or_num_angles-1-j)*npixels_perunit;
02291
02292
02293 draw_rectangle (bg, left_offset, square_height_offset,
02294 scaled_width, npixels_perunit);
02295
02296 hsv2rgb(OR_PREF_TO_DEGREES(j)/180, 1.0, 1.0, &color);
02297
02298 02299 02300 02301 02302 02303
02304 if (value >= 0)
02305 draw_rectangle(color, zero_pixel,
02306 square_height_offset,
02307 MIN((int)(value*val_scale),bin_width),
02308 npixels_perunit);
02309 else
02310 draw_rectangle(color, zero_pixel-MIN((int)(-value*val_scale),bin_width),
02311 square_height_offset,
02312 MIN((int)(-value*val_scale),bin_width),
02313 npixels_perunit);
02314
02315
02316 if (draw_zero)
02317 draw_rectangle (fg, zero_pixel, square_height_offset,
02318 1, npixels_perunit);
02319
02320 }
02321 }
02322
02323
02324
02331 int isInsideCircle( int i, int j, int centeri, int centerj,
02332 double radius, double dummyf, void *dummyv)
02333 {
02334 (void)dummyf; (void)dummyv;
02335
02336 return WITHIN_RADIUS(i-centeri,j-centerj,(radius+circular_radius_trim)*(radius+circular_radius_trim));
02337 }
02338
02339
02340
02347 int inhWeightAbove( int i, int j, int ui, int uj,
02348 double radius, double threshold, void *dummyv)
02349 {
02350 const int idx = LAT_INDEX(ui,uj,i,j,inh_rad,inh_array_width);
02351 (void)radius;
02352 (void)dummyv;
02353
02354
02355 if ( (i<0) || (i>N-1) || (j<0) || (j>N-1) ||
02356 (idx < 0) || (idx >= lat_inh_dimension) )
02357 return 0;
02358 else
02359 return (cortex_map[ui][uj].lat_inh_wts[idx] > threshold );
02360 }
02361
02362
02363
02365 int isAlwaysInside( int i, int j, int centeri, int centerj,
02366 double radius, double dummyf, void *dummyv)
02367 {
02368
02369 (void)i; (void)j; (void)centeri; (void)centerj; (void)radius;
02370 (void)dummyf; (void)dummyv;
02371
02372 return 1;
02373 }
02374
02375
02376
02381 int draw_outline_on_retina( int ui, int uj, int radius, int left_offset, ppm_inside_test_ptr testfn)
02382 {
02383 const int lowi = MAX(ui-radius,ppm_start_x);
02384 const int highi = MIN(ui+radius,ppm_end_x-1);
02385 const int lowj = MAX(uj-radius,ppm_start_y);
02386 const int highj = MIN(uj+radius,ppm_end_y-1);
02387
02388 draw_outline(ppm_foreground_color,
02389 lowi,highi, lowj,highj, ppm_start_x, ppm_start_y,
02390 left_offset,
02391 ppm_scaled_retina_height_offset(),
02392 ppm_scaled_retina_unit_pixels(),
02393 ppm_outline_width,
02394 testfn, ui, uj, radius, 0, NULL);
02395
02396 return ppm_scaled_retina_plot_width();
02397 }
02398
02399
02400
02405 int draw_outline_on_cortex( int ui, int uj, int radius, int left_offset, ppm_inside_test_ptr testfn)
02406 {
02407 const int lowi = MAX(ui-radius,ppm_start_i);
02408 const int highi = MIN(ui+radius,ppm_end_i-1);
02409 const int lowj = MAX(uj-radius,ppm_start_j);
02410 const int highj = MIN(uj+radius,ppm_end_j-1);
02411
02412 draw_outline(ppm_foreground_color,
02413 lowi,highi, lowj,highj, ppm_start_i, ppm_start_j,
02414 left_offset,
02415 ppm_scaled_cortex_height_offset(),
02416 ppm_scaled_cortex_unit_pixels(),
02417 ppm_outline_width,
02418 testfn, ui, uj, radius, ppm_weight_threshold, NULL);
02419
02420 return ppm_scaled_cortex_plot_width();
02421 }
02422
02423
02424
02425 int draw_outline(
02426 XColor color,
02427
02428 int lowi, int highi, int lowj, int highj, int starti, int startj,
02429 int left_offset, int height_offset, int npixels_perunit, int outline_width,
02430
02431 ppm_inside_test_ptr testfn,
02432 int int1, int int2, double float1, double float2, void *otherparams
02433 )
02434 {
02435 int i,j;
02436
02437 color = ppm_get_drawing_color(
02438 left_offset + ( lowi-starti) * npixels_perunit - 1,
02439 left_offset + ((highi-starti)+1) * npixels_perunit ,
02440 height_offset + ( lowj-startj) * npixels_perunit - 1,
02441 height_offset + ((highj-startj)+1) * npixels_perunit ,
02442 color
02443 );
02444
02445 for (i=lowi; i <=highi; i++)
02446 for (j=lowj; j<=highj; j++) {
02447
02448 const int xl = left_offset + (i-starti) * npixels_perunit - 1;
02449 const int xh = left_offset + ((i-starti)+1) * npixels_perunit ;
02450 const int yl = height_offset + (j-startj) * npixels_perunit - 1;
02451 const int yh = height_offset + ((j-startj)+1) * npixels_perunit ;
02452
02453
02454 if ( (testfn)( i, j, int1, int2, float1, float2, otherparams) ) {
02455 02456 02457 02458
02459 const int left_in = ((i-1<lowi) ?0:(testfn)(i-1, j, int1, int2, float1, float2, otherparams));
02460 const int right_in = ((i+1>highi)?0:(testfn)(i+1, j, int1, int2, float1, float2, otherparams));
02461 const int top_in = ((j-1<lowj) ?0:(testfn)(i, j-1, int1, int2, float1, float2, otherparams));
02462 const int bottom_in = ((j+1>highj)?0:(testfn)(i, j+1, int1, int2, float1, float2, otherparams));
02463
02464 int p;
02465
02466 for (p = 0; p < outline_width ; p++) {
02467
02468 if (!left_in)
02469 draw_vertical_line( color, xl-p, yl+(top_in?1:-p), yh+(bottom_in?-1:p));
02470 if (!right_in)
02471 draw_vertical_line( color, xh+p, yl+(top_in?1:-p), yh+(bottom_in?-1:p));
02472 if (!top_in)
02473 draw_horizontal_line(color, xl+1-(left_in?0:p), xh-1+(right_in?0:p), yl-p);
02474 if (!bottom_in)
02475 draw_horizontal_line(color, xl+1-(left_in?0:p), xh-1+(right_in?0:p), yh+p);
02476 }
02477 }
02478 }
02479
02480 return 0;
02481 }
02482
02483
02484
02485
02486
02487
02488
02490 void ppm_draw_pixel(int xi, int yi, XColor color)
02491 {
02492 if ( (yi < 0) || (yi >= IMG_SIZE_Y) ||
02493 (xi < 0) || (xi >= IMG_SIZE_X) )
02494 return;
02495
02496 image[xi][yi] = color;
02497 }
02498
02499
02500
02510 void BhamXDrawLine_PointsAlongX(int xA, int yA, int xB, int yB, int direction, XColor color, int thickness)
02511 {
02512 const int dx = xB - xA;
02513 const int dy = yB - yA;
02514 const int incE = (dy<<1);
02515 const int incSE = incE - (dx<<1);
02516
02517 int d = incE - dx;
02518 int x, y=yA;
02519 int i;
02520
02521 ppm_draw_pixel(xA,yA,color);
02522 for (x = xA; x < xB; x++) {
02523 if (d <= 0 ) {
02524 d += incE;
02525 }
02526 else {
02527 d += incSE;
02528 y += direction;
02529 }
02530 for (i=0; i<thickness; i++)
02531 ppm_draw_pixel(x, y+(direction>0? i : -i),color);
02532 }
02533 }
02534
02535
02536
02537 void BhamXDrawLine_PointsAlongY(int xA, int yA, int xB, int yB, int direction, XColor color, int thickness)
02538 {
02539 const int dx = xB - xA;
02540 const int dy = yB - yA;
02541 const int incE = (dx<<1);
02542 const int incSE = incE - (dy<<1);
02543
02544 int d = incE - dy;
02545 int y, x=xA, yp=yA;
02546 int i;
02547
02548 ppm_draw_pixel(xA,yA,color);
02549 for (y = yA; y < yB; y++) {
02550 yp += direction;
02551 if (d <= 0 ) {
02552 d += incE;
02553 }
02554 else {
02555 d += incSE;
02556 x += 1;
02557 }
02558 for (i=0; i<thickness; i++)
02559 ppm_draw_pixel(x+ (direction>0? i : -i),yp,color);
02560 }
02561 }
02562
02563
02568 void ppm_draw_line(int x_1, int y_1, int x_2, int y_2, XColor color, int thickness)
02569 {
02570 int dx,dy;
02571 int xA,xB,yA,yB;
02572 int y, direction;
02573
02574
02575 dx = x_2 - x_1;
02576 if (dx >= 0) { xA = x_1; yA = y_1; xB = x_2; yB = y_2; }
02577 else { xA = x_2; yA = y_2; xB = x_1; yB = y_1; }
02578
02579
02580 02581 02582
02583 dy = yB - yA;
02584 if (dy > 0) { direction = 1; y = yB; }
02585 else { direction = -1; y = (yA<<1)-yB; }
02586
02587
02588
02589 if (abs(dy) > abs(dx)) BhamXDrawLine_PointsAlongY(xA, yA, xB, y, direction, color, thickness);
02590 else BhamXDrawLine_PointsAlongX(xA, yA, xB, y, direction, color, thickness);
02591 }
02592
02593
02594
02598 void ppm_draw_line_at_angle(int cx, int cy, double angle, double length, double width, XColor color)
02599 {
02600 angle=M_PI-angle;
02601
02602
02603 if (ppm_always_draw_point || (length > 1.0)) {
02604 const int xoffset = (int)((length/2)*cos(angle));
02605 const int yoffset = (int)((length/2)*sin(angle));
02606
02607 color = ppm_get_drawing_color(cx+xoffset, cy+yoffset, cx-xoffset, cy-yoffset, color);
02608
02609 ppm_draw_line( cx+xoffset, cy+yoffset, cx-xoffset, cy-yoffset, color, 1);
02610 if (width>1) {
02611
02612 double delt;
02613 for (delt=0; delt<width/2; delt+=0.5) {
02614 const int deltax=(int)(delt*cos(M_PI/2-angle));
02615 const int deltay=(int)(delt*sin(M_PI/2-angle));
02616 ppm_draw_line( cx+xoffset-deltax, cy+yoffset+deltay, cx-xoffset-deltax, cy-yoffset+deltay, color, 2);
02617 ppm_draw_line( cx+xoffset+deltax, cy+yoffset-deltay, cx-xoffset+deltax, cy-yoffset-deltay, color, 2);
02618 }
02619 }
02620 }
02621 }