00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012 #include "Riostream.h"
00013 #include <cctype>
00014
00015 #ifdef WIN32
00016 #define NOMINMAX
00017 #endif
00018
00019 #include "TVirtualX.h"
00020 #include "TString.h"
00021 #include "TROOT.h"
00022
00023 #include "TGLPlotCamera.h"
00024 #include "TGLParametric.h"
00025 #include "TGLIncludes.h"
00026 #include "TVirtualPad.h"
00027 #include "KeySymbols.h"
00028 #include "Buttons.h"
00029 #include "TString.h"
00030 #include "TColor.h"
00031 #include "TMath.h"
00032
00033
00034
00035
00036
00037
00038
00039
00040
00041
00042
00043
00044
00045
00046
00047
00048
00049
00050
00051
00052
00053
00054
00055
00056
00057
00058 namespace
00059 {
00060
00061
00062 void ReplaceUVNames(TString &equation)
00063 {
00064
00065
00066
00067
00068 using namespace std;
00069 const Ssiz_t len = equation.Length();
00070
00071
00072 Int_t vFound = 0;
00073
00074 for (Ssiz_t i = 0; i < len;) {
00075 const char c = equation[i];
00076 if (!isalpha(c)) {
00077 ++i;
00078 continue;
00079 } else{
00080 ++i;
00081 if (c == 'u' || c == 'v') {
00082
00083
00084 if (i == len || (!isalpha(equation[i]) && !isdigit(equation[i]) && equation[i] != '_')) {
00085
00086 equation[i - 1] = c == 'u' ? 'x' : (++vFound, 'y');
00087 } else {
00088
00089
00090 while (i < len && (isalpha(equation[i]) || isdigit(equation[i]) || equation[i] == '_'))
00091 ++i;
00092 }
00093 } else {
00094 while (i < len && (isalpha(equation[i]) || isdigit(equation[i]) || equation[i] == '_'))
00095 ++i;
00096 }
00097 }
00098 }
00099
00100 if (!vFound)
00101 equation += "+0*y";
00102 }
00103
00104 }
00105
00106 ClassImp(TGLParametricEquation)
00107
00108
00109 TGLParametricEquation::TGLParametricEquation(const TString &name, const TString &xFun, const TString &yFun,
00110 const TString &zFun, Double_t uMin, Double_t uMax,
00111 Double_t vMin, Double_t vMax)
00112 : TNamed(name, name),
00113 fEquation(0),
00114 fURange(uMin, uMax),
00115 fVRange(vMin, vMax),
00116 fConstrained(kFALSE),
00117 fModified(kFALSE)
00118 {
00119
00120
00121
00122
00123 if (!xFun.Length() || !yFun.Length() || !zFun.Length()) {
00124 Error("TGLParametricEquation", "One of string expressions iz empty");
00125 MakeZombie();
00126 return;
00127 }
00128
00129 TString equation(xFun);
00130 equation.ToLower();
00131 ReplaceUVNames(equation);
00132 fXEquation.reset(new TF2(name + "xEquation", equation.Data(), uMin, uMax, vMin, vMax));
00133
00134 if (fXEquation->IsZombie()) {
00135 MakeZombie();
00136 return;
00137 }
00138
00139 equation = yFun;
00140 equation.ToLower();
00141 ReplaceUVNames(equation);
00142 fYEquation.reset(new TF2(name + "yEquation", equation.Data(), uMin, uMax, vMin, vMax));
00143
00144 if (fYEquation->IsZombie()) {
00145 MakeZombie();
00146 return;
00147 }
00148
00149 equation = zFun;
00150 equation.ToLower();
00151 ReplaceUVNames(equation);
00152 fZEquation.reset(new TF2(name + "zEquation", equation.Data(), uMin, uMax, vMin, vMax));
00153
00154 if (fZEquation->IsZombie())
00155 MakeZombie();
00156 }
00157
00158
00159 TGLParametricEquation::TGLParametricEquation(const TString &name, ParametricEquation_t equation,
00160 Double_t uMin, Double_t uMax, Double_t vMin, Double_t vMax)
00161 : TNamed(name, name),
00162 fEquation(equation),
00163 fURange(uMin, uMax),
00164 fVRange(vMin, vMax),
00165 fConstrained(kFALSE),
00166 fModified(kFALSE)
00167 {
00168
00169 if (!fEquation) {
00170 Error("TGLParametricEquation", "Function ptr is null");
00171 MakeZombie();
00172 }
00173 }
00174
00175
00176 Rgl::Range_t TGLParametricEquation::GetURange()const
00177 {
00178
00179 return fURange;
00180 }
00181
00182
00183 Rgl::Range_t TGLParametricEquation::GetVRange()const
00184 {
00185
00186 return fVRange;
00187 }
00188
00189
00190 Bool_t TGLParametricEquation::IsConstrained()const
00191 {
00192
00193 return fConstrained;
00194 }
00195
00196
00197 void TGLParametricEquation::SetConstrained(Bool_t c)
00198 {
00199
00200 fConstrained = c;
00201 }
00202
00203
00204 Bool_t TGLParametricEquation::IsModified()const
00205 {
00206
00207 return fModified;
00208 }
00209
00210
00211 void TGLParametricEquation::SetModified(Bool_t m)
00212 {
00213
00214 fModified = m;
00215 }
00216
00217
00218 void TGLParametricEquation::EvalVertex(TGLVertex3 &newVertex, Double_t u, Double_t v)const
00219 {
00220
00221 if (fEquation)
00222 return fEquation(newVertex, u, v);
00223
00224 if (IsZombie())
00225 return;
00226
00227 newVertex.X() = fXEquation->Eval(u, v);
00228 newVertex.Y() = fYEquation->Eval(u, v);
00229 newVertex.Z() = fZEquation->Eval(u, v);
00230 }
00231
00232
00233 Int_t TGLParametricEquation::DistancetoPrimitive(Int_t px, Int_t py)
00234 {
00235
00236 if (fPainter.get())
00237 return fPainter->DistancetoPrimitive(px, py);
00238 return 9999;
00239 }
00240
00241
00242 void TGLParametricEquation::ExecuteEvent(Int_t event, Int_t px, Int_t py)
00243 {
00244
00245 if (fPainter.get())
00246 return fPainter->ExecuteEvent(event, px, py);
00247 }
00248
00249
00250 char *TGLParametricEquation::GetObjectInfo(Int_t , Int_t ) const
00251 {
00252
00253
00254 static char mess[] = { "parametric surface" };
00255 return mess;
00256 }
00257
00258
00259 void TGLParametricEquation::Paint(Option_t * )
00260 {
00261
00262 if (!fPainter.get())
00263 fPainter.reset(new TGLHistPainter(this));
00264 fPainter->Paint("dummyoption");
00265 }
00266
00267 ClassImp(TGLParametricPlot)
00268
00269
00270 TGLParametricPlot::TGLParametricPlot(TGLParametricEquation *eq,
00271 TGLPlotCamera *camera)
00272 : TGLPlotPainter(camera),
00273 fMeshSize(90),
00274 fShowMesh(kFALSE),
00275 fColorScheme(4),
00276 fEquation(eq)
00277 {
00278
00279 InitGeometry();
00280 InitColors();
00281 }
00282
00283
00284 Bool_t TGLParametricPlot::InitGeometry()
00285 {
00286
00287
00288
00289
00290
00291
00292
00293 if (fMeshSize * fMeshSize != (Int_t)fMesh.size() || fEquation->IsModified()) {
00294 if (fEquation->IsZombie())
00295 return kFALSE;
00296
00297 fEquation->SetModified(kFALSE);
00298
00299 fMesh.resize(fMeshSize * fMeshSize);
00300 fMesh.SetRowLen(fMeshSize);
00301
00302 const Rgl::Range_t uRange(fEquation->GetURange());
00303 const Rgl::Range_t vRange(fEquation->GetVRange());
00304
00305 const Double_t dU = (uRange.second - uRange.first) / (fMeshSize - 1);
00306 const Double_t dV = (vRange.second - vRange.first) / (fMeshSize - 1);
00307 const Double_t dd = 0.001;
00308 Double_t u = uRange.first;
00309
00310 TGLVertex3 min;
00311 fEquation->EvalVertex(min, uRange.first, vRange.first);
00312 TGLVertex3 max(min), newVert, v1, v2;
00313 using namespace TMath;
00314
00315 for (Int_t i = 0; i < fMeshSize; ++i) {
00316 Double_t v = vRange.first;
00317 for (Int_t j = 0; j < fMeshSize; ++j) {
00318 fEquation->EvalVertex(newVert, u, v);
00319 min.X() = Min(min.X(), newVert.X());
00320 max.X() = Max(max.X(), newVert.X());
00321 min.Y() = Min(min.Y(), newVert.Y());
00322 max.Y() = Max(max.Y(), newVert.Y());
00323 min.Z() = Min(min.Z(), newVert.Z());
00324 max.Z() = Max(max.Z(), newVert.Z());
00325
00326 fMesh[i][j].fPos = newVert;
00327
00328 v += dV;
00329 }
00330 u += dU;
00331 }
00332
00333 const Double_t xRange = max.X() - min.X(), yRange = max.Y() - min.Y(), zRange = max.Z() - min.Z();
00334 const Double_t xS = 1. / xRange, yS = 1. / yRange, zS = 1. / zRange;
00335
00336 for (Int_t i = 0; i < fMeshSize; ++i) {
00337 for (Int_t j = 0; j < fMeshSize; ++j) {
00338 TGLVertex3 &ver = fMesh[i][j].fPos;
00339 ver.X() *= xS, ver.Y() *= yS, ver.Z() *= zS;
00340 }
00341 }
00342
00343 if (!xRange || !yRange || !zRange) {
00344 Error("InitGeometry", "Zero axis range");
00345 return kFALSE;
00346 }
00347
00348 u = uRange.first;
00349 for (Int_t i = 0; i < fMeshSize; ++i) {
00350 Double_t v = vRange.first;
00351 for (Int_t j = 0; j < fMeshSize; ++j) {
00352 TGLVertex3 &ver = fMesh[i][j].fPos;
00353 fEquation->EvalVertex(v1, u + dd, v);
00354 fEquation->EvalVertex(v2, u, v + dd);
00355 v1.X() *= xS, v1.Y() *= yS, v1.Z() *= zS;
00356 v2.X() *= xS, v2.Y() *= yS, v2.Z() *= zS;
00357 Normal2Plane(ver.CArr(), v1.CArr(), v2.CArr(), fMesh[i][j].fNormal.Arr());
00358 v += dV;
00359 }
00360 u += dU;
00361 }
00362
00363 using Rgl::Range_t;
00364 fBackBox.SetPlotBox(Range_t(min.X() * xS, max.X() * xS),
00365 Range_t(min.Y() * yS, max.Y() * yS),
00366 Range_t(min.Z() * zS, max.Z() * zS));
00367 if (fCamera) fCamera->SetViewVolume(fBackBox.Get3DBox());
00368 }
00369
00370 return kTRUE;
00371 }
00372
00373
00374 void TGLParametricPlot::StartPan(Int_t px, Int_t py)
00375 {
00376
00377 fMousePosition.fX = px;
00378 fMousePosition.fY = fCamera->GetHeight() - py;
00379 fCamera->StartPan(px, py);
00380 fBoxCut.StartMovement(px, fCamera->GetHeight() - py);
00381 }
00382
00383
00384 void TGLParametricPlot::Pan(Int_t px, Int_t py)
00385 {
00386
00387
00388 if (fSelectedPart) {
00389 SaveModelviewMatrix();
00390 SaveProjectionMatrix();
00391
00392 fCamera->SetCamera();
00393 fCamera->Apply(fPadPhi, fPadTheta);
00394
00395 if (fBoxCut.IsActive() && (fSelectedPart >= kXAxis && fSelectedPart <= kZAxis))
00396 fBoxCut.MoveBox(px, fCamera->GetHeight() - py, fSelectedPart);
00397 else
00398 fCamera->Pan(px, py);
00399
00400 RestoreProjectionMatrix();
00401 RestoreModelviewMatrix();
00402 }
00403
00404 fUpdateSelection = kTRUE;
00405 }
00406
00407
00408 char *TGLParametricPlot::GetPlotInfo(Int_t , Int_t )
00409 {
00410
00411
00412 static char mess[] = { "parametric surface" };
00413 return mess;
00414 }
00415
00416
00417 void TGLParametricPlot::AddOption(const TString &)
00418 {
00419
00420 }
00421
00422
00423 void TGLParametricPlot::ProcessEvent(Int_t event, Int_t , Int_t py)
00424 {
00425
00426
00427 if (event == kButton1Double && fBoxCut.IsActive()) {
00428 fBoxCut.TurnOnOff();
00429 if (!gVirtualX->IsCmdThread())
00430 gROOT->ProcessLineFast(Form("((TGLPlotPainter *)0x%lx)->Paint()", (ULong_t)this));
00431 else
00432 Paint();
00433 } else if (event == kKeyPress) {
00434 if (py == kKey_c || py == kKey_C) {
00435 if (fHighColor)
00436 Info("ProcessEvent", "Switch to true color to use box cut");
00437 else {
00438 fBoxCut.TurnOnOff();
00439 fUpdateSelection = kTRUE;
00440 }
00441 } else if (py == kKey_s || py == kKey_S) {
00442 fColorScheme == 20 ? fColorScheme = -1 : ++fColorScheme;
00443 InitColors();
00444 } else if (py == kKey_w || py == kKey_W) {
00445 fShowMesh = !fShowMesh;
00446 } else if (py == kKey_l || py == kKey_L) {
00447 fMeshSize == kHigh ? fMeshSize = kLow : fMeshSize += 15;
00448 InitGeometry();
00449 InitColors();
00450 }
00451 }
00452 }
00453
00454
00455 void TGLParametricPlot::InitGL()const
00456 {
00457
00458 glEnable(GL_DEPTH_TEST);
00459 glEnable(GL_LIGHTING);
00460 glEnable(GL_LIGHT0);
00461 glDisable(GL_CULL_FACE);
00462 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_TRUE);
00463 }
00464
00465
00466 void TGLParametricPlot::DeInitGL()const
00467 {
00468
00469 glDisable(GL_DEPTH_TEST);
00470 glDisable(GL_LIGHTING);
00471 glDisable(GL_LIGHT0);
00472 glDisable(GL_CULL_FACE);
00473 glLightModeli(GL_LIGHT_MODEL_TWO_SIDE, GL_FALSE);
00474 }
00475
00476
00477 void TGLParametricPlot::DrawPlot()const
00478 {
00479
00480
00481
00482 const Rgl::PlotTranslation trGuard(this);
00483
00484 if (!fSelectionPass) {
00485 SetSurfaceColor();
00486 if (fShowMesh) {
00487 glEnable(GL_POLYGON_OFFSET_FILL);
00488 glPolygonOffset(1.f, 1.f);
00489 }
00490 } else {
00491 Rgl::ObjectIDToColor(fSelectionBase, fHighColor);
00492 }
00493
00494 glBegin(GL_TRIANGLES);
00495
00496 for (Int_t i = 0; i < fMeshSize - 1; ++i) {
00497 for (Int_t j = 0; j < fMeshSize - 1; ++j) {
00498 if (fBoxCut.IsActive()) {
00499 using TMath::Min;
00500 using TMath::Max;
00501 const Double_t xMin = Min(Min(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Min(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
00502 const Double_t xMax = Max(Max(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Max(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
00503 const Double_t yMin = Min(Min(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Min(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
00504 const Double_t yMax = Max(Max(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Max(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
00505 const Double_t zMin = Min(Min(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Min(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
00506 const Double_t zMax = Max(Max(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Max(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
00507
00508 if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
00509 continue;
00510 }
00511
00512 glNormal3dv(fMesh[i + 1][j + 1].fNormal.CArr());
00513 if(fColorScheme != -1)
00514 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i + 1][j + 1].fRGBA);
00515 glVertex3dv(fMesh[i + 1][j + 1].fPos.CArr());
00516
00517 glNormal3dv(fMesh[i][j + 1].fNormal.CArr());
00518 if(fColorScheme != -1)
00519 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i][j + 1].fRGBA);
00520 glVertex3dv(fMesh[i][j + 1].fPos.CArr());
00521
00522 glNormal3dv(fMesh[i][j].fNormal.CArr());
00523 if(fColorScheme != -1)
00524 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i][j].fRGBA);
00525 glVertex3dv(fMesh[i][j].fPos.CArr());
00526
00527 glNormal3dv(fMesh[i + 1][j].fNormal.CArr());
00528 if(fColorScheme != -1)
00529 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i + 1][j].fRGBA);
00530 glVertex3dv(fMesh[i + 1][j].fPos.CArr());
00531
00532 glNormal3dv(fMesh[i + 1][j + 1].fNormal.CArr());
00533 if(fColorScheme != -1)
00534 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i + 1][j + 1].fRGBA);
00535 glVertex3dv(fMesh[i + 1][j + 1].fPos.CArr());
00536
00537 glNormal3dv(fMesh[i][j].fNormal.CArr());
00538 if(fColorScheme != -1)
00539 glMaterialfv(GL_FRONT_AND_BACK, GL_DIFFUSE, fMesh[i][j].fRGBA);
00540 glVertex3dv(fMesh[i][j].fPos.CArr());
00541 }
00542 }
00543
00544 glEnd();
00545
00546 if (!fSelectionPass && fShowMesh) {
00547 glDisable(GL_POLYGON_OFFSET_FILL);
00548 const TGLDisableGuard lightGuard(GL_LIGHTING);
00549 const TGLEnableGuard blendGuard(GL_BLEND);
00550 const TGLEnableGuard smoothGuard(GL_LINE_SMOOTH);
00551
00552 glBlendFunc(GL_SRC_ALPHA, GL_ONE_MINUS_SRC_ALPHA);
00553 glColor4d(0., 0., 0., 0.5);
00554 glPolygonMode(GL_FRONT_AND_BACK, GL_LINE);
00555
00556 for (Int_t i = 0; i < fMeshSize - 1; ++i) {
00557 for (Int_t j = 0; j < fMeshSize - 1; ++j) {
00558 if (fBoxCut.IsActive()) {
00559 using TMath::Min;
00560 using TMath::Max;
00561 const Double_t xMin = Min(Min(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Min(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
00562 const Double_t xMax = Max(Max(fMesh[i][j].fPos.X(), fMesh[i + 1][j].fPos.X()), Max(fMesh[i][j + 1].fPos.X(), fMesh[i + 1][j + 1].fPos.X()));
00563 const Double_t yMin = Min(Min(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Min(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
00564 const Double_t yMax = Max(Max(fMesh[i][j].fPos.Y(), fMesh[i + 1][j].fPos.Y()), Max(fMesh[i][j + 1].fPos.Y(), fMesh[i + 1][j + 1].fPos.Y()));
00565 const Double_t zMin = Min(Min(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Min(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
00566 const Double_t zMax = Max(Max(fMesh[i][j].fPos.Z(), fMesh[i + 1][j].fPos.Z()), Max(fMesh[i][j + 1].fPos.Z(), fMesh[i + 1][j + 1].fPos.Z()));
00567
00568 if (fBoxCut.IsInCut(xMin, xMax, yMin, yMax, zMin, zMax))
00569 continue;
00570 }
00571 glBegin(GL_POLYGON);
00572 glVertex3dv(fMesh[i][j].fPos.CArr());
00573 glVertex3dv(fMesh[i][j + 1].fPos.CArr());
00574 glVertex3dv(fMesh[i + 1][j + 1].fPos.CArr());
00575 glVertex3dv(fMesh[i + 1][j].fPos.CArr());
00576 glEnd();
00577 }
00578 }
00579
00580 glPolygonMode(GL_FRONT_AND_BACK, GL_FILL);
00581 }
00582
00583 if (fBoxCut.IsActive())
00584 fBoxCut.DrawBox(fSelectionPass, fSelectedPart);
00585 }
00586
00587
00588 void TGLParametricPlot::InitColors()
00589 {
00590
00591
00592
00593 if (fColorScheme == -1)
00594 return;
00595
00596 const Rgl::Range_t uRange(fEquation->GetURange());
00597
00598 const Float_t dU = Float_t((uRange.second - uRange.first) / (fMeshSize - 1));
00599 Float_t u = Float_t(uRange.first);
00600
00601 for (Int_t i = 0; i < fMeshSize; ++i) {
00602 for (Int_t j = 0; j < fMeshSize; ++j)
00603 Rgl::GetColor(u, uRange.first, uRange.second, fColorScheme, fMesh[i][j].fRGBA);
00604 u += dU;
00605 }
00606 }
00607
00608
00609 void TGLParametricPlot::DrawSectionXOZ()const
00610 {
00611
00612 }
00613
00614
00615 void TGLParametricPlot::DrawSectionYOZ()const
00616 {
00617
00618 }
00619
00620
00621 void TGLParametricPlot::DrawSectionXOY()const
00622 {
00623
00624 }
00625
00626
00627 void TGLParametricPlot::SetSurfaceColor()const
00628 {
00629
00630 const Float_t specular[] = {1.f, 1.f, 1.f, 1.f};
00631 glMaterialfv(GL_FRONT_AND_BACK, GL_SPECULAR, specular);
00632 glMaterialf(GL_FRONT_AND_BACK, GL_SHININESS, 20.f);
00633
00634 if (fColorScheme == -1) {
00635 const Float_t outerDiff[] = {0.5f, 0.42f, 0.f, 1.f};
00636 glMaterialfv(GL_FRONT, GL_DIFFUSE, outerDiff);
00637 const Float_t innerDiff[] = {0.5f, 0.2f, 0.f, 1.f};
00638 glMaterialfv(GL_BACK, GL_DIFFUSE, innerDiff);
00639 }
00640 }