/***************************************************************************** * * Copyright (c) 1999, KL GROUP INC. All Rights Reserved. * http://www.klgroup.com * * This file is provided for demonstration and educational uses only. * Permission to use, copy, modify and distribute this file for * any purpose and without fee is hereby granted, provided that the * above copyright notice and this permission notice appear in all * copies, and that the name of KL Group not be used in advertising * or publicity pertaining to this material without the specific, * prior written permission of an authorized representative of * KL Group. * * KL GROUP MAKES NO REPRESENTATIONS OR WARRANTIES ABOUT THE SUITABILITY * OF THE SOFTWARE, EITHER EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED * TO THE IMPLIED WARRANTIES OF MERCHANTABILITY, FITNESS FOR A PARTICULAR * PURPOSE, OR NON-INFRINGEMENT. KL GROUP SHALL NOT BE LIABLE FOR ANY * DAMAGES SUFFERED BY USERS AS A RESULT OF USING, MODIFYING OR * DISTRIBUTING THIS SOFTWARE OR ITS DERIVATIVES. * *****************************************************************************/ //--------------------------------------------------------------------------- #include #pragma hdrstop #include "shader1.h" #include //--------------------------------------------------------------------------- #pragma link "OlectraChart3D_TLB" #pragma resource "*.dfm" TfrmShader *frmShader; const float PI = 3.14159265358979; const int SphereSize = 31; const double HoleValue = -100.0; //--------------------------------------------------------------------------- __fastcall TfrmShader::TfrmShader(TComponent* Owner) : TForm(Owner) { } //--------------------------------------------------------------------------- // Setup the Form and the Chart //--------------------------------------------------------------------------- void __fastcall TfrmShader::FormCreate(TObject *Sender) { FirstPass = true; //Start with the form in the top-left corner Top = 5; Left = 5; //Don't all the user to make changes to the Charts chBall->AllowUserChanges = false; Chart3D1->AllowUserChanges = false; //Make the mouse an HourGlass Screen->Cursor = crHourGlass; //Set some default values SweepVal = 45; RiseVal = 45; IntensityVal = 1; AmbientVal = 0; //Initialize the ButtonDown so that the Drag Ball doesn't follow the mouse ButtonDown = mbRight; //Put the mouse back to its default state Screen->Cursor = crDefault; } //--------------------------------------------------------------------------- // More setup of the Chart //--------------------------------------------------------------------------- void __fastcall TfrmShader::FormActivate(TObject *Sender) { if (FirstPass == true) { //Make the mouse an HourGlass Screen->Cursor = crHourGlass; FirstPass = false; //Hide the Drag Ball until the form is ready to be drawn chBall->Visible = false; //Batch all the updates to the Charts so all the changes occur at once Chart3D1->IsBatched = true; chBall->IsBatched = true; //Setup the Charts MakeSphereData(); SetBallDistnLevels(25); SetChartDistnLevels(edLevels->Text.ToInt()); //Resume regular updates on the Drag Ball chBall->IsBatched = false; //Do some last minute setup on the target Chart StartAngle(); ApplyShaded(); //Resume regular updates for the main Chart Chart3D1->IsBatched = false; //Do some last minute setup on the Drag Ball then make it visuble again Variant vBorder = chBall->Border_; vBorder.OlePropertySet("Type", oc3dBorderNone); vBorder.OlePropertySet("Width", 0); Variant vInterior = chBall->Interior_; vInterior.OlePropertySet("BackgroundColor", frmShader->Color); vInterior.OlePropertySet("ForegroundColor", frmShader->Color); chBall->Visible = true; //Set the mouse back to its' default state Screen->Cursor = crDefault; } } //--------------------------------------------------------------------------- // End the program //--------------------------------------------------------------------------- void __fastcall TfrmShader::mnuExitClick(TObject *Sender) { exit(0); } //--------------------------------------------------------------------------- // Apply the new shading values to the main Chart //--------------------------------------------------------------------------- void TfrmShader::ApplyShaded() { //Changes have occured in the Drag Ball's position, so update the Ball and the // target Chart UpdateSphere(); CalcShaded(); } //--------------------------------------------------------------------------- // Based on the Rise and Sweep values, apply shading to the Drag Ball so it // looks like a light source is hitting it //--------------------------------------------------------------------------- void TfrmShader::CalcAngle(int X, int Y) { double xy; double xz; double dx; double dy; double Length; char Buffer[25]; LastX = X; LastY = Y; if ((CenterY == LastY) && (CenterX == LastX)) { xy = 0; } else { if (LastX == CenterX) { if (LastY > CenterY) { xy = (-PI) / 2; } else { xy = PI / 2; } } else { xy = atan((double)(CenterY - LastY) / (double)(LastX - CenterX)); if (LastX < CenterX) { xy = xy + PI; } } xy = xy * 180.0 / PI; xy = (int)xy; if (xy < 0) { xy = xy + 360; } } dx = LastX - CenterX; dy = LastY - CenterY; Length = sqrt(dx * dx + dy * dy); xz = 90.0 * (1 - Length / Radius); if (0.0 > xz) { xz = 0.0; } if (90.0 < xz) { xz = 90.0; } xz = (int)xz; SweepVal = xy; RiseVal = xz; itoa((int)xy, Buffer, 10); edSweep->Text = Buffer; itoa((int)xz, Buffer, 10); edRise->Text = Buffer; UpdateSphere(); } //--------------------------------------------------------------------------- // Calculate the shading used on the Drag Ball and apply it to the target Chart //--------------------------------------------------------------------------- void TfrmShader::CalcShaded() { double xy; double xz; double Scalef; double Ambient; double Intensity; char Buffer[25]; xy = edSweep->Text.ToInt(); xz = edRise->Text.ToInt(); Scalef = edScale->Text.ToInt(); Ambient = scrAmbient->Position / 100.0; Intensity = scrIntensity->Position / 100.0; if (0.0 > xz) { xz = 0.0; } if (90.0 < xz) { xz = 90.0; } itoa((int)xz, Buffer, 10); edRise->Text = Buffer; Variant vCG = Chart3D1->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); Variant vCG1Data = vCG1.OlePropertyGet("ElevationData"); vCG1.OlePropertySet("ContourData", vCG1Data.OleFunction("CreateShaded", xy, xz, Scalef, Ambient, Intensity)); } //--------------------------------------------------------------------------- // Create the data used in the Drag Ball //--------------------------------------------------------------------------- void TfrmShader::MakeSphereData() { int nx, ny; double vx, vy; double vx2, vy2; double v; Variant vCG = chBall->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); Variant vCG1Data = vCG1.OlePropertyGet("ElevationData"); //Batch the updates to the Data object for even better performance vCG1Data.OlePropertySet("IsBatched", true); vCG1Data.OlePropertySet("IsBatched", true); nx = SphereSize; ny = SphereSize; //Setup the Data object for the Drag Ball vCG1Data.OlePropertySet("RowCount", nx); vCG1Data.OlePropertySet("ColumnCount", ny); vCG1Data.OlePropertySet("HoleValue", HoleValue); vCG1Data.OlePropertySet("RowDelta", 1, (2.0 / (nx - 1))); vCG1Data.OlePropertySet("ColumnDelta", 1, (2.0 / (ny - 1))); vCG1Data.OlePropertySet("RowOrigin", -1.0); vCG1Data.OlePropertySet("ColumnOrigin", -1.0); //Actually generate the data for (int i = 1; i <= nx; i++) { vx = -1 + 2 * (i - 1) / (double)(nx - 1); vx2 = vx * vx; for (int j = 1; j <= ny; j++) { vy = -1 + 2 * (j - 1) / (double)(ny - 1); vy2 = vy * vy; v = 1 - vx2 - vy2; if (v < 0) { vCG1Data.OlePropertySet("Value", i, j, HoleValue); } else { vCG1Data.OlePropertySet("Value", i, j, sqrt(v)); } } //for j } //for i //Go back to normal updates of the Data object vCG1Data.OlePropertySet("IsBatched", false); } //--------------------------------------------------------------------------- // Set the distribution levels on the Drag Ball //--------------------------------------------------------------------------- void TfrmShader::SetBallDistnLevels(int Levels) { Variant vCG = chBall->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); Variant vContour = vCG1.OlePropertyGet("Contour"); Variant vSurface = vContour.OlePropertyGet("Levels"); vSurface.OlePropertySet("IsDefault", true); vSurface.OlePropertySet("NumLevels", 0); for (int i = 1; i <= Levels; i++) { vSurface.OleFunction("Add", (i * (1.0 / (Levels + 1)))); } } //--------------------------------------------------------------------------- // Set the distribution levels on the target Chart //--------------------------------------------------------------------------- void TfrmShader::SetChartDistnLevels(int Levels) { Variant vCG = Chart3D1->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); Variant vContour = vCG1.OlePropertyGet("Contour"); Variant vSurface = vContour.OlePropertyGet("Levels"); vSurface.OlePropertySet("IsDefault", true); vSurface.OlePropertySet("NumLevels", 0); for (int i = 1; i <= Levels; i++) { vSurface.OleFunction("Add", (i * (1.0 / (Levels + 1)))); } } //--------------------------------------------------------------------------- // Do some calculations based on the data in the Drag Ball //--------------------------------------------------------------------------- void TfrmShader::StartAngle() { double dx, dy; int px, py; Variant vCG = chBall->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); vCG1.OleFunction("DataCoordToCoord", 0.0, 0.0, 1.0, &px, &py); CenterX = px; CenterY = py; vCG1.OleFunction("DataCoordToCoord", 1.0, 0.0, 0.0, &px, &py); dx = px - CenterX; dy = py - CenterY; Radius = sqrt(dx * dx + dy * dy); } //--------------------------------------------------------------------------- // Update the Drag Ball based on the Rise and Sweep values //--------------------------------------------------------------------------- void TfrmShader::UpdateSphere() { double xy, xz; double Ambient, Intensity; xy = SweepVal; xz = RiseVal; Ambient = AmbientVal; Intensity = IntensityVal; Variant vCG = chBall->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); Variant vCG1Data = vCG1.OlePropertyGet("ElevationData"); vCG1.OlePropertySet("ContourData", vCG1Data.OleFunction("CreateShaded", xy, xz, 1.0, Ambient, Intensity)); } //--------------------------------------------------------------------------- // Don't allow any user defined Actions to occur //--------------------------------------------------------------------------- void __fastcall TfrmShader::chBallModifyStart(TObject *Sender, VARIANT_BOOL *IsOK) { *IsOK = false; } //--------------------------------------------------------------------------- // Allow the user to interact with the target Chart if it is in 3D mode //--------------------------------------------------------------------------- void __fastcall TfrmShader::Chart3D1ModifyStart(TObject *Sender, VARIANT_BOOL *IsOK) { *IsOK = chk3D->Checked; } //--------------------------------------------------------------------------- // Make sure only the Left Mouse-Button allows the interaction //--------------------------------------------------------------------------- void __fastcall TfrmShader::chBallMouseDown(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Button == mbLeft) { CalcAngle(X, Y); ButtonDown = mbLeft; } } //--------------------------------------------------------------------------- // Only make changes to the Drag Ball if the Left Mouse-Button is being held //--------------------------------------------------------------------------- void __fastcall TfrmShader::chBallMouseMove(TObject *Sender, TShiftState Shift, int X, int Y) { if (ButtonDown == mbLeft) { CalcAngle(X, Y); } } //--------------------------------------------------------------------------- // Set the holding variable to something other than a Left Mouse-Button so // the Chart does not think that a Left Mouse-Button is being held when it is not //--------------------------------------------------------------------------- void __fastcall TfrmShader::chBallMouseUp(TObject *Sender, TMouseButton Button, TShiftState Shift, int X, int Y) { if (Button == mbLeft) { CalcAngle(X, Y); ButtonDown = mbRight; } } //--------------------------------------------------------------------------- // Apply the changes that the user has requested //--------------------------------------------------------------------------- void __fastcall TfrmShader::cmdApplyClick(TObject *Sender) { //Make the mouse an HourGlass Screen->Cursor = crHourGlass; //Batch all the updates to the Charts so all the changes occur at once Chart3D1->IsBatched = true; chBall->IsBatched = true; //Setup the distribution Levels that the user has chosen SetChartDistnLevels(edLevels->Text.ToInt()); //Apply the shading from the Drag Ball to the target Chart ApplyShaded(); Variant vCG = Chart3D1->ChartGroups; Variant vCG1 = vCG.OlePropertyGet("Item", 1); Variant vCG1Data = vCG1.OlePropertyGet("Elevation"); vCG1Data.OlePropertySet("IsShaded", chk3D->Checked); //Change the fill method depending on the users choice if (chkCellFill->Checked) { Variant vContour = vCG1.OlePropertyGet("Contour"); vContour.OlePropertySet("ZoneMethod", oc3dZoneCells); } else { Variant vContour = vCG1.OlePropertyGet("Contour"); vContour.OlePropertySet("ZoneMethod", oc3dZoneContours); } //Resume regular updates to the Charts chBall->IsBatched = false; Chart3D1->IsBatched = false; //Set the mouse back to its' default state Screen->Cursor = crDefault; } //--------------------------------------------------------------------------- // Update the Drag Ball with the new Intensity setting //--------------------------------------------------------------------------- void __fastcall TfrmShader::scrIntensityScroll(TObject *Sender, TScrollCode ScrollCode, int &ScrollPos) { IntensityVal = scrIntensity->Position / 100.0; lblIValue->Caption = IntensityVal; UpdateSphere(); } //--------------------------------------------------------------------------- // Update the Drag Ball with the new Ambient setting //--------------------------------------------------------------------------- void __fastcall TfrmShader::scrAmbientScroll(TObject *Sender, TScrollCode ScrollCode, int &ScrollPos) { AmbientVal = scrAmbient->Position / 100.0; lblAValue->Caption = AmbientVal; UpdateSphere(); } //--------------------------------------------------------------------------- // End the program //--------------------------------------------------------------------------- void __fastcall TfrmShader::cmdExitClick(TObject *Sender) { exit(0); } //--------------------------------------------------------------------------- // Limit the characters allowed during value entry //--------------------------------------------------------------------------- void __fastcall TfrmShader::edLevelsKeyPress(TObject *Sender, char &Key) { //Limit the entered characters to 0-9, Tab, Backspace and Enter if (((Key < '0') || (Key > '9')) && (Key != 8) && (Key != 9) && (Key != 13)) { Key = 0; } } //--------------------------------------------------------------------------- // Validate the value on loss of Focus //--------------------------------------------------------------------------- void __fastcall TfrmShader::edLevelsExit(TObject *Sender) { //Make sure the value entered is not larger than 100 if (edLevels->Text.ToInt() > 100) { edLevels->Text = "100"; } } //--------------------------------------------------------------------------- // Limit the characters allowed during value entry //--------------------------------------------------------------------------- void __fastcall TfrmShader::edRiseKeyPress(TObject *Sender, char &Key) { //Limit the entered characters to 0-9, Tab, Backspace and Enter if (((Key < '0') || (Key > '9')) && (Key != 8) && (Key != 9) && (Key != 13)) { Key = 0; } } //--------------------------------------------------------------------------- // Validate the value on loss of Focus //--------------------------------------------------------------------------- void __fastcall TfrmShader::edRiseExit(TObject *Sender) { //Make sure the value entered is not larger than 90 if (edRise->Text.ToInt() > 90) { edRise->Text = "90"; } RiseVal = edRise->Text.ToInt(); UpdateSphere(); } //--------------------------------------------------------------------------- // Limit the characters allowed during value entry //--------------------------------------------------------------------------- void __fastcall TfrmShader::edScaleKeyPress(TObject *Sender, char &Key) { //Limit the entered characters to 0-9, Tab, Backspace, Enter and the decimal if (((Key < '0') || (Key > '9')) && (Key != 8) && (Key != 9) && (Key != 13) && (Key != 46)) { Key = 0; } } //--------------------------------------------------------------------------- // Validate the value on loss of Focus //--------------------------------------------------------------------------- void __fastcall TfrmShader::edScaleExit(TObject *Sender) { //Make sure the value entered is not less than 0 if (edScale->Text.ToInt() < 0) { edScale->Text = "0"; } } //--------------------------------------------------------------------------- // Limit the characters allowed during value entry //--------------------------------------------------------------------------- void __fastcall TfrmShader::edSweepKeyPress(TObject *Sender, char &Key) { //Limit the entered characters to 0-9, Tab, Backspace and Enter if (((Key < '0') || (Key > '9')) && (Key != 8) && (Key != 9) && (Key != 13)) { Key = 0; } } //--------------------------------------------------------------------------- // Validate the value on loss of Focus //--------------------------------------------------------------------------- void __fastcall TfrmShader::edSweepExit(TObject *Sender) { //Make sure the value entered is not larger than 360 if (edSweep->Text.ToInt() > 360) { edSweep->Text = "360"; } SweepVal = edSweep->Text.ToInt(); UpdateSphere(); } //--------------------------------------------------------------------------- // Show the 'About This Demo' Help Page //--------------------------------------------------------------------------- void __fastcall TfrmShader::mnuAboutThisDemoClick(TObject *Sender) { Application->HelpContext(16); } //--------------------------------------------------------------------------- // Show the 'About Olectra Chart' Help Page //--------------------------------------------------------------------------- void __fastcall TfrmShader::mnuAboutOlectraChartClick(TObject *Sender) { Application->HelpContext(19); } //---------------------------------------------------------------------------