static void menu_cb_pitchSettings (EDITOR_ARGS) {
	EDITOR_IAM (FormantGridEditor);
	EDITOR_FORM (L"Source pitch settings", 0)
		LABEL (L"", L"These settings apply to the pitch curve")
		LABEL (L"", L"that you hear when playing the FormantGrid.")
		REAL (L"Starting time", L"0.0%")
		POSITIVE (L"Starting pitch (Hz)", L"150.0")
		REAL (L"Mid time", L"25.0%")
		POSITIVE (L"Mid pitch (Hz)", L"180.0")
		REAL (L"End time", L"100.0%")
		POSITIVE (L"End pitch (Hz)", L"120")
	EDITOR_OK
		SET_REAL (L"Starting time", my source.pitch.tStart)
		SET_REAL (L"Starting pitch", my source.pitch.f0Start)
		SET_REAL (L"Mid time", my source.pitch.tMid)
		SET_REAL (L"Mid pitch", my source.pitch.f0Mid)
		SET_REAL (L"End time", my source.pitch.tEnd)
		SET_REAL (L"End pitch", my source.pitch.f0End)
	EDITOR_DO
		preferences.source.pitch.tStart = my source.pitch.tStart = GET_REAL (L"Starting time");
		preferences.source.pitch.f0Start = my source.pitch.f0Start = GET_REAL (L"Starting pitch");
		preferences.source.pitch.tMid = my source.pitch.tMid = GET_REAL (L"Mid time");
		preferences.source.pitch.f0Mid = my source.pitch.f0Mid = GET_REAL (L"Mid pitch");
		preferences.source.pitch.tEnd = my source.pitch.tEnd = GET_REAL (L"End time");
		preferences.source.pitch.f0End = my source.pitch.f0End = GET_REAL (L"End pitch");
	EDITOR_END
}
Esempio n. 2
0
static void menu_cb_pitchSettings (EDITOR_ARGS) {
	EDITOR_IAM (FormantGridEditor);
	EDITOR_FORM (U"Source pitch settings", 0)
		LABEL (U"", U"These settings apply to the pitch curve")
		LABEL (U"", U"that you hear when playing the FormantGrid.")
		REAL     (U"Starting time",       my default_source_pitch_tStart  ())
		POSITIVE (U"Starting pitch (Hz)", my default_source_pitch_f0Start ())
		REAL     (U"Mid time",            my default_source_pitch_tMid    ())
		POSITIVE (U"Mid pitch (Hz)",      my default_source_pitch_f0Mid   ())
		REAL     (U"End time",            my default_source_pitch_tEnd    ())
		POSITIVE (U"End pitch (Hz)",      my default_source_pitch_f0End   ())
	EDITOR_OK
		SET_REAL (U"Starting time",  my p_source_pitch_tStart)
		SET_REAL (U"Starting pitch", my p_source_pitch_f0Start)
		SET_REAL (U"Mid time",       my p_source_pitch_tMid)
		SET_REAL (U"Mid pitch",      my p_source_pitch_f0Mid)
		SET_REAL (U"End time",       my p_source_pitch_tEnd)
		SET_REAL (U"End pitch",      my p_source_pitch_f0End)
	EDITOR_DO
		my pref_source_pitch_tStart  () = my p_source_pitch_tStart  = GET_REAL (U"Starting time");
		my pref_source_pitch_f0Start () = my p_source_pitch_f0Start = GET_REAL (U"Starting pitch");
		my pref_source_pitch_tMid    () = my p_source_pitch_tMid    = GET_REAL (U"Mid time");
		my pref_source_pitch_f0Mid   () = my p_source_pitch_f0Mid   = GET_REAL (U"Mid pitch");
		my pref_source_pitch_tEnd    () = my p_source_pitch_tEnd    = GET_REAL (U"End time");
		my pref_source_pitch_f0End   () = my p_source_pitch_f0End   = GET_REAL (U"End pitch");
	EDITOR_END
}
Esempio n. 3
0
void Terrain::addTriangle(point4 p1, point4 p2, point4 p3, color4 high, color4 mid, color4 low, color4 brown){

    point4 p1_new = point4(p1.x, p1.y, POSITIVE(p1.z), p1.w);
    point4 p2_new = point4(p2.x, p2.y, POSITIVE(p2.z), p2.w);
    point4 p3_new = point4(p3.x, p3.y, POSITIVE(p3.z), p3.w);
    vec4 u = p2_new - p1_new;
    vec4 v = p3_new - p1_new;
    vec3 normal = -normalize( cross(u, v) );

    if (this->points.size() < this->num_points + 5){
        this->points.resize(2*this->points.size());
        this->normals.resize(2*this->points.size());
        this->colors.resize(2*this->points.size());
    }

    points[this->num_points] = p1_new;
    normals[this->num_points] = normal;
    if (p1.z == 0){
        colors[this->num_points++] = low;
    } else if (p1.z > -0.5*this->range){
        colors[this->num_points++] = mid;
    } else if (p1.z > -0.75*this->range){
        colors[this->num_points++] = brown;
    } else {
        colors[this->num_points++] = high;
    }
    points[this->num_points] = p2_new;
    normals[this->num_points] = normal;
    if (p2.z == 0){
        colors[this->num_points++] = low;
    } else if (p2.z > -0.5*this->range){
        colors[this->num_points++] = mid;
    } else if (p3.z > -0.75*this->range){
        colors[this->num_points++] = brown;
    } else {
        colors[this->num_points++] = high;
    }
    points[this->num_points] = p3_new;
    normals[this->num_points] = normal;
    if (p3.z == 0){
        colors[this->num_points++] = low;
    } else if (p3.z > -0.5*this->range){
        colors[this->num_points++] = mid;
    } else if (p3.z > -0.75*this->range){
        colors[this->num_points++] = brown;
    } else {
        colors[this->num_points++] = high;
    }
}
Esempio n. 4
0
/* assume that b points to at least 2 chars            */
uint
to_index( char * b )
{
  if( b[1] == '+' )
    return POSITIVE( *b );
  else
    return NEGATIVE( *b );
} /**~ end to_index ~**/
Esempio n. 5
0
/*
 * graphical equaliser using the function eq to boost/cut the stream.
 */
void BandPassFilterFFT::EQ(uint8_t *stream, double(*eq)(double, void*), void *args)
{
	double band_data[2*samples];

	/*
	 * EQ the data
	 */
	for(uint32_t i=0; i<=freqs; i++) // Go over each frequency.
	{
		double Eq = eq(f[i], args);
		REAL(band_data,POSITIVE(i,samples)) = Eq * REAL(fcache,POSITIVE(i,samples));
		IMAG(band_data,POSITIVE(i,samples)) = Eq * IMAG(fcache,POSITIVE(i,samples));
		REAL(band_data,NEGATIVE(i,samples)) = Eq * REAL(fcache,NEGATIVE(i,samples));
		IMAG(band_data,NEGATIVE(i,samples)) = Eq * IMAG(fcache,NEGATIVE(i,samples));
	}

	fft_inverse(band_data, stream);
}
static void menu_cb_setDynamicRange (EDITOR_ARGS) {
	EDITOR_IAM (SpectrumEditor);
	EDITOR_FORM (L"Set dynamic range", 0)
		POSITIVE (L"Dynamic range (dB)", my default_dynamicRange ())
	EDITOR_OK
		SET_REAL (L"Dynamic range", my p_dynamicRange)
	EDITOR_DO
		my pref_dynamicRange () = my p_dynamicRange = GET_REAL (L"Dynamic range");
		updateRange (me);
		FunctionEditor_redraw (me);
	EDITOR_END
}
Esempio n. 7
0
static void menu_cb_setCeiling (EDITOR_ARGS) {
    EDITOR_IAM (PitchEditor);
    EDITOR_FORM (L"Change ceiling", 0)
    POSITIVE (L"Ceiling (Hz)", L"600")
    EDITOR_OK
    Pitch pitch = (Pitch) my data;
    SET_REAL (L"Ceiling", pitch -> ceiling)
    EDITOR_DO
    Pitch pitch = (Pitch) my data;
    Editor_save (me, L"Change ceiling");
    Pitch_setCeiling (pitch, GET_REAL (L"Ceiling"));
    FunctionEditor_redraw (me);
    my broadcastDataChanged ();
    EDITOR_END
}
Esempio n. 8
0
static void menu_cb_ExtractSelectedSoundForOverlap (TimeSoundEditor me, EDITOR_ARGS_FORM) {
	EDITOR_FORM (U"Extract selected sound for overlap)", nullptr)
		WORD (U"Name", U"slice")
		POSITIVE (U"Overlap (s)", my default_extract_overlap ())
	EDITOR_OK
		SET_REAL (U"Overlap", my pref_extract_overlap ())
	EDITOR_DO
		Sound sound = my d_sound.data;
		Melder_assert (sound);
		my pref_extract_overlap () = GET_REAL (U"Overlap");
		autoSound extract = Sound_extractPartForOverlap (sound, my d_startSelection, my d_endSelection,
			my pref_extract_overlap ());
		Thing_setName (extract.peek(), GET_STRING (U"Name"));
		Editor_broadcastPublication (me, extract.transfer());
	EDITOR_END
}
static void menu_cb_addPointAt (FormantGridEditor me, EDITOR_ARGS_FORM) {
	EDITOR_FORM (U"Add point", nullptr)
		REAL (U"Time (s)", U"0.0")
		POSITIVE (U"Frequency (Hz)", U"200.0")
	EDITOR_OK
		SET_REAL (U"Time", 0.5 * (my d_startSelection + my d_endSelection))
		SET_REAL (U"Frequency", my ycursor)
	EDITOR_DO
		Editor_save (me, U"Add point");
		FormantGrid grid = (FormantGrid) my data;
		Ordered tiers = my editingBandwidths ? grid -> bandwidths.get() : grid -> formants.get();
		RealTier tier = (RealTier) tiers -> item [my selectedFormant];
		RealTier_addPoint (tier, GET_REAL (U"Time"), GET_REAL (U"Frequency"));
		FunctionEditor_redraw (me);
		Editor_broadcastDataChanged (me);
	EDITOR_END
}
Esempio n. 10
0
static void menu_cb_addPointAt (EDITOR_ARGS) {
	EDITOR_IAM (FormantGridEditor);
	EDITOR_FORM (L"Add point", 0)
		REAL (L"Time (s)", L"0.0")
		POSITIVE (L"Frequency (Hz)", L"200.0")
	EDITOR_OK
		SET_REAL (L"Time", 0.5 * (my startSelection + my endSelection))
		SET_REAL (L"Frequency", my ycursor)
	EDITOR_DO
		Editor_save (me, L"Add point");
		FormantGrid grid = (FormantGrid) my data;
		Ordered tiers = my editingBandwidths ? grid -> bandwidths : grid -> formants;
		RealTier tier = (RealTier) tiers -> item [my selectedFormant];
		RealTier_addPoint (tier, GET_REAL (L"Time"), GET_REAL (L"Frequency"));
		FunctionEditor_redraw (me);
		my broadcastDataChanged ();
	EDITOR_END
}
Esempio n. 11
0
BBox Transform::operator()(const BBox& b) const {
#if 1
	const Transform &M = *this;
	BBox ret(M(Point(b.pmin.x, b.pmin.y, b.pmin.z)));
	ret = combine(ret, M(Point(b.pmax.x, b.pmin.y, b.pmin.z)));
	ret = combine(ret, M(Point(b.pmin.x, b.pmax.y, b.pmin.z)));
	ret = combine(ret, M(Point(b.pmin.x, b.pmin.y, b.pmax.z)));
	ret = combine(ret, M(Point(b.pmin.x, b.pmax.y, b.pmax.z)));
	ret = combine(ret, M(Point(b.pmax.x, b.pmax.y, b.pmin.z)));
	ret = combine(ret, M(Point(b.pmax.x, b.pmin.y, b.pmax.z)));
	ret = combine(ret, M(Point(b.pmax.x, b.pmax.y, b.pmax.z)));
	return ret;
#else
	// note the fact that the eight corner points are linear combinations 
	//	of three axis-aligned basis vectors and a single corner point
	// PBRT p104 exercise 2.1
	const Transform & T = *this;
	auto d = b.pmax - b.pmin;
	auto x = T(Vec3(d.x, 0, 0));
	auto y = T(Vec3(0, d.y, 0));
	auto z = T(Vec3(0, 0, d.z));
	auto pmin = T(b.pmin);
	auto pmax = pmin;
#define NEGTIVE(v) ((v) < 0 ? (v) : 0)
#define POSITIVE(v) ((v) > 0 ? (v) : 0)
	pmin.x += NEGTIVE(x.x) + NEGTIVE(y.x) + NEGTIVE(z.x);
	pmin.y += NEGTIVE(x.y) + NEGTIVE(y.y) + NEGTIVE(z.y);
	pmin.z += NEGTIVE(x.z) + NEGTIVE(y.z) + NEGTIVE(z.z);
	pmax.x += POSITIVE(x.x) + POSITIVE(y.x) + POSITIVE(z.x);
	pmax.y += POSITIVE(x.y) + POSITIVE(y.y) + POSITIVE(z.y);
	pmax.z += POSITIVE(x.z) + POSITIVE(y.z) + POSITIVE(z.z);
#undef NEGTIVE
#undef POSITIVE
	//return BBox(pmin, pmin + x + y + z);
	return BBox(pmin, pmax);
#endif
}
Esempio n. 12
0
float
get_action_cost (int pos)
{
  float tot = 0.0;


  if (pos < 0)
    return 0.0;

  if (GpG.optimize == OPT_ACT_COST)
    tot = gef_conn[pos].cost;
  else if (GpG.optimize == OPT_PLAN_SIMILARITY)
    tot = POSITIVE (gef_conn[pos].cost);
  else
    tot = 1.0;

  return (tot);
}
Esempio n. 13
0
int Printer_postScriptSettings (void) {
	static UiForm *dia;
	if (dia == NULL) {
		UiForm::UiField *radio;
		dia = new UiForm (theCurrentPraatApplication -> topShell, L"PostScript settings", DO_Printer_postScriptSettings, NULL, L"PostScript settings...", L"PostScript settings...");
		#if defined (_WIN32) || defined (macintosh)
			BOOLEAN (L"Allow direct PostScript", TRUE);
		#endif
		RADIO_ENUM (L"Grey resolution", kGraphicsPostscript_spots, DEFAULT)
		#if defined (UNIX)
			RADIO_ENUM (L"Paper size", kGraphicsPostscript_paperSize, DEFAULT);
			RADIO_ENUM (L"Orientation", kGraphicsPostscript_orientation, DEFAULT);
			POSITIVE (L"Magnification", L"1.0");
			LABEL (L"label", L"Print command:");
			#if defined (linux)
				TEXTFIELD (L"printCommand", L"lpr %s");
			#else
				TEXTFIELD (L"printCommand", L"lp -c %s");
			#endif
		#endif
		RADIO_ENUM (L"Font choice strategy", kGraphicsPostscript_fontChoiceStrategy, DEFAULT);
		#if defined (macintosh)
			BOOLEAN (L"EPS files include preview", TRUE);
		#endif
		dia->finish ();
	}
	#if defined (_WIN32) || defined (macintosh)
		SET_INTEGER (L"Allow direct PostScript", thePrinter. allowDirectPostScript);
	#endif
	SET_ENUM (L"Grey resolution", kGraphicsPostscript_spots, thePrinter. spots);
	#if defined (UNIX)
		SET_ENUM (L"Paper size", kGraphicsPostscript_paperSize, thePrinter. paperSize);
		SET_ENUM (L"Orientation", kGraphicsPostscript_orientation, thePrinter. orientation);
		SET_REAL (L"Magnification", thePrinter. magnification);
		SET_STRING (L"printCommand", Site_getPrintCommand ());
	#endif
	SET_ENUM (L"Font choice strategy", kGraphicsPostscript_fontChoiceStrategy, thePrinter. fontChoiceStrategy);
	#if defined (macintosh)
		SET_INTEGER (L"EPS files include preview", thePrinter. epsFilesHavePreview);
	#endif
	dia->do_ (false);
	return 1;
}
Esempio n. 14
0
static void menu_cb_soundScaling (TimeSoundEditor me, EDITOR_ARGS_FORM) {
	EDITOR_FORM (U"Sound scaling", nullptr)
		OPTIONMENU_ENUM (U"Scaling strategy", kTimeSoundEditor_scalingStrategy, my default_sound_scalingStrategy ())
		LABEL (U"", U"For \"fixed height\":");
		POSITIVE (U"Height", my default_sound_scaling_height ())
		LABEL (U"", U"For \"fixed range\":");
		REAL (U"Minimum", my default_sound_scaling_minimum ())
		REAL (U"Maximum", my default_sound_scaling_maximum ())
	EDITOR_OK
		SET_ENUM (U"Scaling strategy", kTimeSoundEditor_scalingStrategy, my p_sound_scalingStrategy)
		SET_REAL (U"Height", my p_sound_scaling_height)
		SET_REAL (U"Minimum", my p_sound_scaling_minimum)
		SET_REAL (U"Maximum", my p_sound_scaling_maximum)
	EDITOR_DO
		my pref_sound_scalingStrategy () = my p_sound_scalingStrategy = GET_ENUM (kTimeSoundEditor_scalingStrategy, U"Scaling strategy");
		my pref_sound_scaling_height  () = my p_sound_scaling_height  = GET_REAL (U"Height");
		my pref_sound_scaling_minimum () = my p_sound_scaling_minimum = GET_REAL (U"Minimum");
		my pref_sound_scaling_maximum () = my p_sound_scaling_maximum = GET_REAL (U"Maximum");
		FunctionEditor_redraw (me);
	EDITOR_END
}
Esempio n. 15
0
float
get_action_time (int pos, int level)
{
  float tot;


  if (pos < 0)
    return 0.0;

  if (!GpG.durative_actions_in_domain)
    return STRIPS_ACTIONS_DURATION;


  if (GpG.variable_duration && level >= 0)


    if (vectlevel[level] != NULL && gef_conn[pos].duration_rvals != NULL)
      {

	eval_comp_var_non_recursive (gef_conn[pos].dur_var_index,
				     vectlevel[level]->numeric->values,
				     vectlevel[level]->numeric->values, level,
				     level);
	gef_conn[pos].duration =
	  vectlevel[level]->numeric->values[gef_conn[pos].dur_var_index];

	gef_conn[pos].duration = ROUND_TO_1_1000 (gef_conn[pos].duration);

      }

  if (GpG.optimize == OPT_ACT_COST)
    tot = gef_conn[pos].duration;
  else if (GpG.optimize == OPT_PLAN_SIMILARITY)
    tot = POSITIVE (gef_conn[pos].duration);
  else
    tot = 1.0;

  return (tot);

}
Esempio n. 16
0
static void menu_cb_ExtractSelectedSound_windowed (TimeSoundEditor me, EDITOR_ARGS_FORM) {
	EDITOR_FORM (U"Extract selected sound (windowed)", nullptr)
		WORD (U"Name", U"slice")
		OPTIONMENU_ENUM (U"Window shape", kSound_windowShape, my default_extract_windowShape ())
		POSITIVE (U"Relative width", my default_extract_relativeWidth ())
		BOOLEAN (U"Preserve times", my default_extract_preserveTimes ())
	EDITOR_OK
		SET_ENUM (U"Window shape", kSound_windowShape, my pref_extract_windowShape ())
		SET_REAL (U"Relative width", my pref_extract_relativeWidth ())
		SET_INTEGER (U"Preserve times", my pref_extract_preserveTimes ())
	EDITOR_DO
		Sound sound = my d_sound.data;
		Melder_assert (sound);
		my pref_extract_windowShape () = GET_ENUM (kSound_windowShape, U"Window shape");
		my pref_extract_relativeWidth () = GET_REAL (U"Relative width");
		my pref_extract_preserveTimes () = GET_INTEGER (U"Preserve times");
		autoSound extract = Sound_extractPart (sound, my d_startSelection, my d_endSelection, my pref_extract_windowShape (),
			my pref_extract_relativeWidth (), my pref_extract_preserveTimes ());
		Thing_setName (extract.peek(), GET_STRING (U"Name"));
		Editor_broadcastPublication (me, extract.transfer());
	EDITOR_END
}
Esempio n. 17
0
static void menu_cb_pathFinder (EDITOR_ARGS) {
    EDITOR_IAM (PitchEditor);
    EDITOR_FORM (L"Path finder", 0)
    REAL (L"Silence threshold", L"0.03")
    REAL (L"Voicing threshold", L"0.45")
    REAL (L"Octave cost", L"0.01")
    REAL (L"Octave-jump cost", L"0.35")
    REAL (L"Voiced/unvoiced cost", L"0.14")
    POSITIVE (L"Ceiling (Hz)", L"600")
    BOOLEAN (L"Pull formants", 0)
    EDITOR_OK
    Pitch pitch = (Pitch) my data;
    SET_REAL (L"Ceiling", pitch -> ceiling)
    EDITOR_DO
    Pitch pitch = (Pitch) my data;
    Editor_save (me, L"Path finder");
    Pitch_pathFinder (pitch,
                      GET_REAL (L"Silence threshold"), GET_REAL (L"Voicing threshold"),
                      GET_REAL (L"Octave cost"), GET_REAL (L"Octave-jump cost"),
                      GET_REAL (L"Voiced/unvoiced cost"), GET_REAL (L"Ceiling"), GET_INTEGER (L"Pull formants"));
    FunctionEditor_redraw (me);
    my broadcastDataChanged ();
    EDITOR_END
}
Esempio n. 18
0
/*
 * using the frequency fft data, band pass between frequencies in f[bandlo] <= f <= f[bandhi]
 */
void BandPassFilterFFT::band_window(double *band_data, uint32_t bandhi, uint32_t bandlo)
{
	/*
	 * Split the data in to frequency bands.
	 */
	for(uint32_t i=0; i<=freqs; i++) // Go over each frequency...
	{
		if ((i <= bandhi) && (i>=bandlo)) // ...and copy over the frequencies in the the band window...
		{
			REAL(band_data,POSITIVE(i,samples)) = REAL(fcache,POSITIVE(i,samples));
			IMAG(band_data,POSITIVE(i,samples)) = IMAG(fcache,POSITIVE(i,samples));
			REAL(band_data,NEGATIVE(i,samples)) = REAL(fcache,NEGATIVE(i,samples));
			IMAG(band_data,NEGATIVE(i,samples)) = IMAG(fcache,NEGATIVE(i,samples));
		}
		else // ...and set the other frequencies to zero.
		{
			REAL(band_data,POSITIVE(i,samples)) = 0.;
			IMAG(band_data,POSITIVE(i,samples)) = 0.;
			REAL(band_data,NEGATIVE(i,samples)) = 0.;
			IMAG(band_data,NEGATIVE(i,samples)) = 0.;
		}
	}
}
Esempio n. 19
0
int
main( int argc, char ** argv )
{
  /* Vars */
  uint i, j, k;
  node block;

  /* check to make sure an input file was supplied      */
  /* get the number of blocks (the first line of input) */
  /* I am just assuming that the input will always be   */
  /* correct since this is for a competition            */
  if( argc == 2)
    get_num_blocks(argv[1]);
  else
    exit(EXIT_FAILURE);

  /* Initialize the graph and cycles arrays */
  /* The graph array is an incidence matrix */
  /* if graph(i,j) is true, then there is a */
  /* directed edge from i -> j              */
  for( i = 0; i < SIZE; ++i )
    {
      for( j = 0; j < SIZE; ++j )
	{
	  graph[i][j] = NO_CONN;
	}
    }
  
  /* Get the input blocks */
  for( i = 0; i < num_blocks; ++i )
    {
      /* for each block... */
      if( get_block( &block ) > 2 )
	{
	  /* if the block has more than 2 '00' terms then just skip it */
	  /* if the block has 3 or 4 sides with '00' terms then it     */
	  /* cannot connect to anything so it doesn't matter           */
	  continue;
	}
      /* else // block has less than 2 zeros                           */

      /* if a block matches itself, then the structure is unbounded    */
      /* We wouldn't have to do this, but it is a simple enough check  */
      /* and as n -> 40,000 it can save a lot of time                  */
      for( k = 0; k < 4; ++k )
	{
	  for( j = 0; j < 4; ++j )
	    {
	      if( block[k*2] == block[j*2] && block[k*2+1] != block[j*2+1] )
		  goto unbounded;
	    }
	}

      /* else // block does not match itself */
      /* add links to the graph              */
      for( j = 0; j < 4; ++j )
	{
	  /* For each side... */

	  /* assume correct formatting so only need to test first block for if 0 */
	  if( block[j*2] == '0' )
	    {
	      /* no links can be added */
	      continue;
	    }
	  else
	    {
	      for( k = 0; k < 4; ++k )
		{
		  /* for every other side on the block... */
		  if( j == k ) /* same side we are already on, so continue */
		    continue;
		  else if( block[k*2] == '0' ) /* side is 00 so continue */
		    continue;
		  /* else add link */
		  /* The basic idea for the links is, add a directed edge */
		  /* between the opposite of that side (i.d. opposite of  */
		  /* P- is P+) to each of the other sides on the block.   */
		  /* This is because if you can connect to the current    */
		  /* side of the block (i.d. block[j*2]) then you will    */
		  /* connect with the opposite of this block, and it will */
		  /* connect you to any of the other sides of the current */
		  /* block.                                               */
		  /* The problem is actually pretty nice since you can    */
		  /* rotate and reflect, the geometry of the block doesnt */
		  /* actually matter.                                     */
		  if( block[j*2+1] == '+' )
		    graph[ NEGATIVE( block[j*2] ) ][ to_index( &block[k*2] ) ] = 1;
		  /* else the block is negative */
		  else
		    graph[ POSITIVE( block[j*2] ) ][ to_index( &block[k*2] ) ] = 1;
		}
	    }
	}

      /* turn on __DEBUG__ if you want to see the graph */
      print_graph();
    }

  /* graph is all set up, just check for cycles */
  if( traverse() )
    goto unbounded; /* U mad bro? */

  /* if we made it here then it is a bounded structure */
      printf("bounded\n");
      exit(EXIT_SUCCESS);

    unbounded:
      printf("unbounded\n");
      exit(EXIT_SUCCESS);
} /**~ end main ~**/