// ========================================================================== // 2002 // SLUIS - A MEDIEVAL FORTIFIED TOWN IN THE NETHERLANDS // A DIGITAL ELEVATION MODEL // A RENDERING CHALLENGE // // Right or left clicking the image will produce a topographic profile. // Setting top and bottom elevation will constrain the color ramp. // RENDER will re-render the color ramped image. // TURN PROBE ON/OFF will/won't show the elevation at any point. // Setting interval will select those elevations to be painted. // CONTOUR will paint those elevations +/- 6% the color WHITE. // STEREO will render RED + CYAN = CYAN and CYAN + RED = RED. // CORRECTED will render RED + CYAN = WHITE. // Setting the grid size will set the spacing for stereo points. // POINT STEREO will render RED + CYAN = CYAN and CYAN + RED = RED. // CORRECTED Point Stereo will render RED + CYAN = WHITE. // ========================================================================== #include #pragma hdrstop #include "Unit1.h" #include #include //--------------------------------------------------------------------------- #pragma package(smart_init) #pragma resource "*.dfm" TForm1 *Form1; //--------------------------------------------------------------------------- __fastcall TForm1::TForm1(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- // ================================================================ VARIABLES int sluis[492][563]; char cyan[492][563]; char red [492][563]; int topElevation = 2000; int bottomElevation = 0; int interval = 50; int gridSize = 10; int elevation; int topleft, bottomright; bool probeOn = false; // ==============================================================SET DEFAULTS void setDefaults (void) { Form1->EditTopElevation->Text = topElevation; Form1->EditBottomElevation->Text = bottomElevation; } // ==================================================== CLEAR RED/CYAN ARRAYS void clearRedCyan (void) { for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { cyan[lat][lon] = 0; red[lat][lon] = 0; } } } // ======================================================= OPEN FILE FUNCTION void open (void) { if (Form1->OpenDialog1->Execute()) { ifstream infile(Form1->OpenDialog1->FileName.c_str()); for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { infile >> sluis[lat][lon]; } Form1->ProgressBar->Position = lat; } infile.close(); } Form1->ProgressBar->Position = 0; } // ===================================================== COLOR RAMP FUNCTION int colorRamp (int range, int value) { if (range==0) range=1; if (value < 0) value = 0; // interesting if deleted if (value > range) value = range; // interesting if deleted int pixelDistanceAlongPath = (value*1792)/range; int red, green, blue; if (pixelDistanceAlongPath < 256) { red=0; green=0; blue=pixelDistanceAlongPath; } else if (pixelDistanceAlongPath < 512) { red=0; green=pixelDistanceAlongPath-256; blue=255; } else if (pixelDistanceAlongPath < 768) { red=0; green=255; blue=255-(pixelDistanceAlongPath-512); } else if (pixelDistanceAlongPath < 1024) { red=(pixelDistanceAlongPath-768); green=255; blue=0; } else if (pixelDistanceAlongPath < 1280) { red= 255; green= 255-(pixelDistanceAlongPath-1024); blue=0; } else if (pixelDistanceAlongPath < 1536) { red=255; green=0; blue=pixelDistanceAlongPath-1280; } else { red=255; green=pixelDistanceAlongPath-1536; blue=255; } return (RGB(red,green,blue)); } // ===========================================================RENDER FUNCTION void render (void) { Form1->Cursor = crHourGlass; Application->ProcessMessages(); for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { Form1->Canvas-> Pixels[lat][lon] = static_cast (colorRamp(topElevation - bottomElevation, sluis[lat][lon] - bottomElevation)); } } Form1->Cursor = crDefault; } // ========================================================= CONTOUR FUNCTION void contour (void) { Form1->Cursor = crHourGlass; Application->ProcessMessages(); for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { if (sluis[lat][lon] % interval < interval / 6) { Form1->Canvas->Pixels[lat][lon] = clWhite; } } } Form1->Cursor = crDefault; } // ================================================== CONTOUR STEREO FUNCTION void contourStereo (void) { Form1->Cursor = crHourGlass; Application->ProcessMessages(); // Color everything black for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { Form1->Canvas->Pixels[lat][lon] = clBlack; } } for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { elevation = sluis[lat][lon]; if (elevation % interval < interval / 6) { if (random(2) == 0) { Form1->Canvas->Pixels[lat-(elevation/150)][lon] = clAqua; Form1->Canvas->Pixels[lat+(elevation/150)][lon] = clRed; } else { Form1->Canvas->Pixels[lat+(elevation/150)][lon] = clRed; Form1->Canvas->Pixels[lat-(elevation/150)][lon] = clAqua; } } } } Form1->Cursor = crDefault; } // ======================================== CORRECTED CONTOUR STEREO FUNCTION void contourStereoCorrected (void) { Form1->Cursor = crHourGlass; Application->ProcessMessages(); clearRedCyan(); int redLat; int cyanLat; // Put red and cyan dots into separate arrays for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { elevation = sluis[lat][lon]; if (elevation % interval < interval / 6) { // correct for out-of-bounds indeces cyanLat = lat - (elevation/150); if (cyanLat > 491) cyanLat = 491; if (cyanLat < 0) cyanLat = 0; redLat = lat + (elevation/150); if (redLat > 491) redLat = 491; if (redLat < 0) redLat = 0; cyan[cyanLat][lon] = 1; red[redLat][lon] = 1; } } } // Combine the two arrays to give four colors: black, white, cyan, red for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { if (cyan[lat][lon] == 1 && red[lat][lon] == 1) { Form1->Canvas->Pixels[lat][lon] = clWhite; } if (cyan[lat][lon] == 1 && red[lat][lon] == 0) { Form1->Canvas->Pixels[lat][lon] = clAqua; } if (cyan[lat][lon] == 0 && red[lat][lon] == 1) { Form1->Canvas->Pixels[lat][lon] = clRed; } if (cyan[lat][lon] == 0 && red[lat][lon] == 0) { Form1->Canvas->Pixels[lat][lon] = clBlack; } } } Form1->Cursor = crDefault; } // =================================================== POINT STEREO FUNCTION void pointStereo (void) { Form1->Cursor = crHourGlass; Application->ProcessMessages(); // Color everything black for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { Form1->Canvas->Pixels[lat][lon] = clBlack; } } for (int lat = 0; lat < 492; lat = lat + gridSize) { for (int lon = 0; lon < 563; lon = lon + gridSize) { elevation = sluis[lat][lon]; if (random(2) == 0) { Form1->Canvas->Pixels[lat-(elevation/150)][lon] = clAqua; Form1->Canvas->Pixels[lat+(elevation/150)][lon] = clRed; } else { Form1->Canvas->Pixels[lat+(elevation/150)][lon] = clRed; Form1->Canvas->Pixels[lat-(elevation/150)][lon] = clAqua; } } } Form1->Cursor = crDefault; } // ========================================== CORRECTED POINT STEREO FUNCTION void pointStereoCorrected (void) { Form1->Cursor = crHourGlass; Application->ProcessMessages(); clearRedCyan(); int redLat; int cyanLat; // Put red and cyan dots into separate arrays for (int lat = 0; lat < 492; lat = lat + gridSize) { for (int lon = 0; lon < 563; lon = lon + gridSize) { elevation = sluis[lat][lon]; // register RED indeces in red array redLat = lat + (elevation/150); if (redLat > 491) redLat = 491; if (redLat < 0) redLat = 0; red[redLat][lon] = 1; // register CYAN indeces in cyan array cyanLat = lat - (elevation/150); if (cyanLat > 491) cyanLat = 491; if (cyanLat < 0) cyanLat = 0; cyan[cyanLat][lon] = 1; } } // Combine the two arrays to give four colors: black, white, cyan, red for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { if (cyan[lat][lon] == 1 && red[lat][lon] == 1) { Form1->Canvas->Pixels[lat][lon] = clWhite; } if (cyan[lat][lon] == 1 && red[lat][lon] == 0) { Form1->Canvas->Pixels[lat][lon] = clAqua; } if (cyan[lat][lon] == 0 && red[lat][lon] == 1) { Form1->Canvas->Pixels[lat][lon] = clRed; } if (cyan[lat][lon] == 0 && red[lat][lon] == 0) { Form1->Canvas->Pixels[lat][lon] = clBlack; } } } Form1->Cursor = crDefault; } // =================================================== RENDER SHADOW FUNCTION void shadow (void) { for (int lat = 1; lat < 491; lat++) { for (int lon = 1; lon < 562; lon++) { topleft = sluis[lat - 1][lon - 1]; bottomright = sluis[lat + 1][lon + 1]; // if downhill render in black if (sluis[lat][lon] < topleft && bottomright < sluis[lat][lon]) { Form1->Canvas->Pixels[lat][lon] = clBlack; } // if uphill render in white else if (sluis[lat][lon] > topleft && bottomright > sluis[lat][lon]) { Form1->Canvas->Pixels[lat][lon] = clWhite; } // if otherwise render in gray else { Form1->Canvas->Pixels[lat][lon] = clSilver; } } } } // ===================================================== RENDER GRAY FUNCTION void gray (void) { int grayLevel; for (int lat = 0; lat < 492; lat++) { for (int lon = 0; lon < 563; lon++) { grayLevel = 255 * (sluis[lat][lon]) / 1000; if (grayLevel > 255) grayLevel = 255; Form1->Canvas->Pixels[lat][lon] = static_cast(RGB(grayLevel, grayLevel, grayLevel)); } } } // --------------------------------------------------------- OPEN FILE BUTTON void __fastcall TForm1::ButtonOpenFileClick(TObject *Sender) { open(); } //--------------------------------------------------- TOP ELEVATION TRACK BAR void __fastcall TForm1::TrackBarTopElevationChange(TObject *Sender) { topElevation = TrackBarTopElevation->Position; Form1->EditTopElevation->Text = topElevation; } //------------------------------------------------ BOTTOM ELEVATION TRACK BAR void __fastcall TForm1::TrackBarBottomElevationChange(TObject *Sender) { bottomElevation = TrackBarBottomElevation->Position; Form1->EditBottomElevation->Text = bottomElevation; } //------------------------------------------------------------- RENDER BUTTON void __fastcall TForm1::ButtonRenderClick(TObject *Sender) { render(); } //-------------------------------------------------- TURN PROBE ON/OFF BUTTON void __fastcall TForm1::ButtonProbeClick(TObject *Sender) { probeOn = !probeOn; if (probeOn) { Form1->ButtonProbe->Caption = "Turn Probe Off"; Form1->Cursor = crCross; } else { Form1->ButtonProbe->Caption = "Turn Probe On"; Form1->Cursor = crDefault; } } //------------------------------------------------------ Render Shadow Button void __fastcall TForm1::ButtonShadowClick(TObject *Sender) { shadow(); } //-------------------------------------------------------- Render Gray Button void __fastcall TForm1::ButtonGrayClick(TObject *Sender) { gray(); } //------------------------------------------------ CONTOUR INTERVAL TRACK BAR void __fastcall TForm1::TrackBarContourChange(TObject *Sender) { interval = TrackBarContour->Position; EditContour->Text = interval; } //------------------------------------------------------------ CONTOUR BUTTON void __fastcall TForm1::ButtonContourClick(TObject *Sender) { contour(); } //----------------------------------------------------- CONTOUR STEREO BUTTON void __fastcall TForm1::ButtonStereoClick(TObject *Sender) { contourStereo(); } //------------------------------------------- CORRECTED CONTOUR STEREO BUTTON void __fastcall TForm1::ButtonContourStereoCorrectedClick(TObject *Sender) { contourStereoCorrected(); } //------------------------------------------------------- GRID SIZE TRACK BAR void __fastcall TForm1::TrackBarGridSizeChange(TObject *Sender) { gridSize = TrackBarGridSize->Position; EditGridSize->Text = gridSize; } //------------------------------------------------------- POINT STEREO BUTTON void __fastcall TForm1::ButtonPointStereoClick(TObject *Sender) { pointStereo(); } //--------------------------------------------- CORRECTED POINT STEREO BUTTON void __fastcall TForm1::ButtonPointStereoCorrectedClick(TObject *Sender) { pointStereoCorrected(); } //------------------------------------------------------------- ON PAINT FORM void __fastcall TForm1::FormPaint(TObject *Sender) { setDefaults(); } //---------------------------------------------------------- MOUSE MOVE FORM void __fastcall TForm1::FormMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (probeOn && X < 492 && Y < 563) { Form1->Cursor = crCross; EditProbeElevation->Text = sluis[X][Y]; } else { Form1->Cursor = crDefault; } } //----------------------------------------------------------- MOUSE DOWN FORM void __fastcall TForm1::FormMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (X < 492 && Y < 563) { // if left button is pressed if (Button == 0) { for (int lat = 0; lat < 492; lat++) { Form1->Canvas->Pixels[lat][Y] = clWhite; Form1->Canvas->Pixels[lat][Y + 1] = clBlack; Form1->Canvas->Pixels[lat][Y - 1] = clBlack; for (int lon = Y - 2; lon > (Y - sluis[lat][Y]/20 + 1); lon --) { Form1->Canvas->Pixels[lat][lon] = clWhite; } Form1->Canvas->Pixels[lat][Y - sluis[lat][Y]/20] = clYellow; Form1->Canvas->Pixels[lat][Y - sluis[lat][Y]/20 + 1] = clRed; Form1->Canvas->Pixels[lat][Y - sluis[lat][Y]/20 - 1] = clRed; } } // if right button is pressed if (Button == 1) { for (int lon = 0; lon < 563; lon++) { Form1->Canvas->Pixels[X][lon] = clWhite; Form1->Canvas->Pixels[X + 1][lon] = clBlack; Form1->Canvas->Pixels[X - 1][lon] = clBlack; for (int lat = X + 2; lat < X + sluis[X][lon]/20 - 1; lat ++) { Form1->Canvas->Pixels[lat][lon] = clWhite; } Form1->Canvas->Pixels[X + sluis[X][lon]/20][lon] = clYellow; Form1->Canvas->Pixels[X + sluis[X][lon]/20 + 1][lon] = clRed; Form1->Canvas->Pixels[X + sluis[X][lon]/20 - 1][lon] = clRed; } } } } //----------------------------------------------------------------------- END