00001 #include "DisplacedTriangle.h"
00002
00003 using namespace std;
00004
00005 namespace rcrt
00006 {
00007
00008 DisplacedTriangle::DisplacedTriangle(Vertex* av,Vertex* bv,Vertex* cv, SolidObject* parent) : Triangle(av,bv,cv,parent)
00009 {
00010 da = Point3D(a->pos() + ((a->normal() / (a->normal() * faceNormal)) * parent->getMaxDispl()));
00011 db = Point3D(b->pos() + ((b->normal() / (b->normal() * faceNormal)) * parent->getMaxDispl()));
00012 dc = Point3D(c->pos() + ((c->normal() / (c->normal() * faceNormal)) * parent->getMaxDispl()));
00013
00014 box.extend(da);
00015 box.extend(a->pos() + (faceNormal * (parent->getMaxDispl() + 100*numeric_limits<float>::epsilon())));
00016 box.extend(db);
00017 box.extend(b->pos() + (faceNormal * (parent->getMaxDispl() + 100*numeric_limits<float>::epsilon())));
00018 box.extend(dc);
00019 box.extend(c->pos() + (faceNormal * (parent->getMaxDispl() + 100*numeric_limits<float>::epsilon())));
00020
00021 upper = new Triangle(new Vertex(da,a->normal()),new Vertex(db,b->normal()),new Vertex(dc,c->normal()),parent);
00022
00023 ab = new ConvexQuad(parent,a->pos(),b->pos(),db,da);
00024 bc = new ConvexQuad(parent,b->pos(),c->pos(),dc,db);
00025 ca = new ConvexQuad(parent,c->pos(),a->pos(),da,dc);
00026
00027 triangles = new vector<Triangle*>();
00028
00029 int N = parent->getDisplDens();
00030
00031 for (int i = 0; i < N; i++) {
00032 for (int j = 0; j < N; j++) {
00033 for (int k = 0; k < N; k++) {
00034 if (i+j+k == N-1) {
00035 std::cout << "lower" << std::endl;
00036 Point2D uv1 = Point2D(j/N,k/N);
00037 Point2D uv2 = Point2D((j+1)/N,k/N);
00038 Point2D uv3 = Point2D(j/N,(k+1)/N);
00039
00040 Point3D po1 = getDispPoint(uv1);
00041 Point3D po2 = getDispPoint(uv2);
00042 Point3D po3 = getDispPoint(uv3);
00043
00044 Vec3D sno = (po2 - po1).crossP(po3 - po1).normalize();
00045 Triangle* t = new Triangle(po1,po2,po3,sno,parent);
00046
00047
00048 triangles->push_back(t);
00049 }
00050
00051 if (i+j+k == N-2) {
00052 std::cout << "upper" << std::endl;
00053 Point2D uv1 = Point2D(j/N,(k+1)/N);
00054 Point2D uv2 = Point2D((j+1)/N,k/N);
00055 Point2D uv3 = Point2D((j+1)/N,(k+1)/N);
00056
00057 Point3D po1 = getDispPoint(uv1);
00058 Point3D po2 = getDispPoint(uv2);
00059 Point3D po3 = getDispPoint(uv3);
00060
00061 Vec3D sno = (po2 - po1).crossP(po3 - po1).normalize();
00062 Triangle* t = new Triangle(po1,po2,po3,sno,parent);
00063
00064
00065 triangles->push_back(t);
00066 }
00067 }
00068 }
00069 }
00070
00071 tree.setTraceables(triangles);
00072 }
00073
00074 DisplacedTriangle::~DisplacedTriangle()
00075 {
00076 if (ab) delete ab;
00077 if (bc) delete bc;
00078 if (ca) delete ca;
00079
00080 if (upper) delete upper;
00081 }
00082
00083 Intersection DisplacedTriangle::baseIntersect(Ray& ray) const
00084 {
00085 ray.tris++;
00086 const Vec3D edge1 = b->pos()-a->pos();
00087 const Vec3D edge2 = c->pos()-a->pos();
00088
00089 const Vec3D pvec = ray.dir().crossP(edge2);
00090
00091 const float det = edge1 * pvec;
00092 if (fabs(det) < numeric_limits<float>::epsilon()) return Intersection();
00093
00094 const float inv_det = 1.0f / det;
00095
00096 const Vec3D tvec = ray.org()-a->pos();
00097 float lambda = tvec * pvec;
00098 lambda *= inv_det;
00099
00100 if (lambda < 0.0f || lambda > 1.0f) return Intersection();
00101
00102 const Vec3D qvec = tvec.crossP(edge1);
00103 float mue = ray.dir() * qvec;
00104 mue *= inv_det;
00105
00106 if (mue < 0.0f || mue+lambda > 1.0f) return Intersection();
00107
00108 float f = edge2 * qvec;
00109 f = f * inv_det - numeric_limits<float>::epsilon();
00110 if (ray.maxDist() <= f || f < numeric_limits<float>::epsilon() ) return Intersection();
00111
00112
00113
00114 bool flip = ray.dir()*faceNormal >= numeric_limits<float>::epsilon();
00115
00116 return Intersection(f, this, ray.atDistance(f), lambda, mue, flip);
00117 }
00118
00119 Intersection DisplacedTriangle::intersect(Ray& ray) const
00120 {
00121
00122
00123
00124 Intersection is;
00125
00126 for(std::vector<Triangle*>::iterator i = triangles->begin(); i != triangles->end(); ++i) {
00127 is = (*i)->intersect(ray);
00128 if (is.isValid()) {
00129 return is;
00130 }
00131 }
00132
00133 if (is.isValid()) {
00134 is.setPrimitive(this);
00135 return is;
00136 }
00137
00138 return Intersection();
00139
00140
00141 if (!box.intersect(ray).isValid())
00142 return Intersection();
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152 float N = parent->getDisplDens();
00153
00154
00155 Intersection topIs, bottomIs, abIs, bcIs, caIs, nearIs, farIs;
00156 topIs = upper->intersect(ray);
00157 bottomIs = baseIntersect(ray);
00158
00159
00160
00161
00162
00163
00164
00165
00166 if (false && (topIs.isValid() || bottomIs.isValid())) {
00167
00168 nearIs = topIs.isValid() ? topIs : bottomIs;
00169 Intersection is = nearIs;
00170 is.setPrimitive(this);
00171 is.setSNormalL(Vec3D(1,1,1));
00172 return is;
00173 }
00174
00175 if (!(topIs.isValid() && bottomIs.isValid())) {
00176 if(topIs.isValid() || bottomIs.isValid()) {
00177 nearIs = topIs.isValid() ? topIs : bottomIs;
00178 }
00179
00180 abIs = ab->intersect(ray);
00181 bcIs = bc->intersect(ray);
00182 caIs = ca->intersect(ray);
00183
00184
00185
00186 if (false && (abIs.isValid() || bcIs.isValid() || caIs.isValid())) {
00187 Intersection is = nearIs;
00188 is.setPrimitive(this);
00189
00190 return is;
00191 }
00192
00193 if (abIs.isValid() && abIs.getDistance() < nearIs.getDistance()) {
00194
00195 farIs = nearIs;
00196 nearIs = abIs;
00197 }
00198 else if (abIs.isValid() && abIs.getDistance() < farIs.getDistance()) {
00199
00200 farIs = abIs;
00201 }
00202 if (bcIs.isValid() && bcIs.getDistance() < nearIs.getDistance()) {
00203
00204 farIs = nearIs;
00205 nearIs = bcIs;
00206 }
00207 else if (bcIs.isValid() && bcIs.getDistance() < farIs.getDistance()) {
00208
00209 farIs = bcIs;
00210 }
00211 if (caIs.isValid() && caIs.getDistance() < nearIs.getDistance()) {
00212
00213 farIs = nearIs;
00214 nearIs = caIs;
00215 }
00216 else if (caIs.isValid() && caIs.getDistance() < farIs.getDistance()) {
00217
00218 farIs = caIs;
00219 }
00220 }
00221 else {
00222 if(topIs.getDistance() < bottomIs.getDistance()) {
00223 nearIs = topIs;
00224 farIs = bottomIs;
00225 }
00226 else {
00227 nearIs = bottomIs;
00228 farIs = topIs;
00229 }
00230 }
00231
00232
00233
00234 if (!(nearIs.isValid() && farIs.isValid())) {
00235
00236
00237
00238
00239
00240 return Intersection();
00241 }
00242
00243 if (false) {
00244 Intersection is = nearIs;
00245 is.setPrimitive(this);
00246 is.setSNormalL(Vec3D(1,1,1));
00247 return is;
00248 }
00249
00250
00251
00252 int i = 0,iStop = N,j = 0,jStop = N,k = 0,kStop = N;
00253
00254 int lastChange = 0;
00255
00256 Point3D subPA, subPB, subPC;
00257 Vec3D subNC;
00258 Point2D uva, uvb, uvc;
00259 bool rightOfC = false;
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269 if (nearIs.getPrimitive() == this || nearIs.getPrimitive() == upper) {
00270
00271
00272
00273
00274
00275
00276
00277 const Point2D& bcoord = nearIs.getParams();
00278 float beta = bcoord[0];
00279 float gamma = bcoord[1];
00280
00281
00282 i = floor((1-beta-gamma) * N);
00283 j = floor(beta * N);
00284 k = floor(gamma * N);
00285
00286
00287
00288
00289 if (i+j+k == N-1) {
00290
00291
00292
00293
00294
00295
00296 Point2D tuva = Point2D(j/N,k/N);
00297 Point2D tuvb = Point2D((j+1)/N,k/N);
00298 Point2D tuvc = Point2D(j/N,(k+1)/N);
00299
00300 Point3D la = getPoint(tuva);
00301 Point3D lb = getPoint(tuvb);
00302 Point3D lc = getPoint(tuvc);
00303 Point3D ua = upper->getPoint(tuva);
00304 Point3D ub = upper->getPoint(tuvb);
00305 Point3D uc = upper->getPoint(tuvc);
00306
00307
00308
00309 Point3D ta = getDispPoint(tuva);
00310 Point3D tb = getDispPoint(tuvb);
00311 Point3D tc = getDispPoint(tuvc);
00312
00313 ConvexQuad testAB(parent,la,lb,ub,ua);
00314 ConvexQuad testBC(parent,lb,lc,uc,ub);
00315 ConvexQuad testCA(parent,lc,la,ua,uc);
00316
00317 if (testAB.intersect(ray).isValid()) {
00318
00319
00320 lastChange = 0;
00321 subPA = tb; subPB = tc; subPC = ta; uva = tuvb; uvb = tuvc; uvc = tuva;
00322 }
00323 else if (testBC.intersect(ray).isValid()) {
00324
00325
00326 lastChange = 4;
00327 subPA = tc; subPB = ta; subPC = tb; uva = tuvc; uvb = tuva; uvc = tuvb;
00328 }
00329 else if (testCA.intersect(ray).isValid()) {
00330
00331
00332 lastChange = 0;
00333 subPA = tb; subPB = tc; subPC = ta; uva = tuvb; uvb = tuvc; uvc = tuva;
00334 }
00335 else {
00336
00337 lastChange = 0;
00338 subPA = tb; subPB = tc; subPC = ta; uva = tuvb; uvb = tuvc; uvc = tuva;
00339 iStop = i; jStop = j; kStop = k;
00340 }
00341 }
00342
00343
00344 if (i+k+j == N-2) {
00345
00346
00347
00348
00349
00350
00351 Point2D tuva = Point2D(j/N,(k+1)/N);
00352 Point2D tuvb = Point2D((j+1)/N,k/N);
00353 Point2D tuvc = Point2D((j+1)/N,(k+1)/N);
00354
00355 Point3D la = getPoint(tuva);
00356 Point3D lb = getPoint(tuvb);
00357 Point3D lc = getPoint(tuvc);
00358 Point3D ua = upper->getPoint(tuva);
00359 Point3D ub = upper->getPoint(tuvb);
00360 Point3D uc = upper->getPoint(tuvc);
00361
00362 Point3D ta = getDispPoint(tuva);
00363 Point3D tb = getDispPoint(tuvb);
00364 Point3D tc = getDispPoint(tuvc);
00365
00366
00367
00368 ConvexQuad testAB(parent,la,lb,ub,ua);
00369 ConvexQuad testBC(parent,lb,lc,uc,ub);
00370 ConvexQuad testCA(parent,lc,la,ua,uc);
00371
00372 if (testAB.intersect(ray).isValid()) {
00373
00374
00375 lastChange = 1;
00376 subPA = tb; subPB = tc; subPC = ta; uva = tuvb; uvb = tuvc; uvc = tuva;
00377 }
00378 else if (testBC.intersect(ray).isValid()) {
00379
00380
00381 lastChange = 3;
00382 subPA = ta; subPB = tb; subPC = tc; uva = tuva; uvb = tuvb; uvc = tuvc;
00383 }
00384 else if (testCA.intersect(ray).isValid()) {
00385
00386
00387 lastChange = 3;
00388 subPA = ta; subPB = tb; subPC = tc; uva = tuva; uvb = tuvb; uvc = tuvc;
00389 }
00390 else {
00391
00392 lastChange = 0;
00393 subPA = tb; subPB = tc; subPC = ta; uva = tuvb; uvb = tuvc; uvc = tuva;
00394 iStop = i; jStop = j; kStop = k;
00395 }
00396 }
00397 }
00398
00399 else {
00400
00401
00402
00403
00404 if(nearIs.getPrimitive() == ab) {
00405 Point3D p = nearIs.getPosition();
00406 Vec3D v = p - a->pos();
00407 Vec3D orthInSide = (da - a->pos()).crossP(b->pos()-a->pos()).crossP(b->pos() - a->pos()).normalize();
00408 orthInSide = orthInSide * (orthInSide * faceNormal);
00409 Vec3D vp = orthInSide * (v * orthInSide);
00410
00411 float f = fabs(vp.norm());
00412 Point3D aAl = a->pos() + (da - a->pos()) * f;
00413 Point3D bAl = b->pos() + (db - b->pos()) * f;
00414 float x = (bAl - aAl).norm();
00415 float y = (p - aAl).norm();
00416 float ratio = y / x;
00417
00418
00419
00420
00421 float alpha = 1 - ratio;
00422 float beta = ratio;
00423 float gamma = 0;
00424
00425
00426 i = floor(alpha * N);
00427 j = floor(beta * N);
00428 k = floor(gamma * N);
00429
00430
00431 Point2D tuva = Point2D(j/N,k/N);
00432 Point2D tuvb = Point2D((j+1)/N,k/N);
00433 Point2D tuvc = Point2D(j/N,(k+1)/N);
00434
00435 Point3D ta = getDispPoint(tuva);
00436 Point3D tb = getDispPoint(tuvb);
00437 Point3D tc = getDispPoint(tuvc);
00438
00439 lastChange = 2;
00440 subPA = ta; subPB = tb; subPC = tc; uva = tuva; uvb = tuvb; uvc = tuvc;
00441 }
00442 else if(nearIs.getPrimitive() == bc) {
00443 Point3D p = nearIs.getPosition();
00444 Vec3D v = p - b->pos();
00445 Vec3D orthInSide = (db - b->pos()).crossP(c->pos()-b->pos()).crossP(c->pos() - b->pos()).normalize();
00446 orthInSide = orthInSide * (orthInSide * faceNormal);
00447 Vec3D vp = orthInSide * (v * orthInSide);
00448 float f = fabs(vp.norm());
00449 Point3D bAl = b->pos() + (db - b->pos()) * f;
00450 Point3D cAl = c->pos() + (dc - c->pos()) * f;
00451 float x = (cAl - bAl).norm();
00452 float y = (p - bAl).norm();
00453 float ratio = y / x;
00454
00455
00456
00457
00458 float alpha = 0;
00459 float beta = 1 - ratio;
00460 float gamma = ratio;
00461
00462
00463 i = floor(alpha * N);
00464 j = floor(beta * N);
00465 k = floor(gamma * N);
00466
00467
00468 Point2D tuva = Point2D(j/N,k/N);
00469 Point2D tuvb = Point2D((j+1)/N,k/N);
00470 Point2D tuvc = Point2D(j/N,(k+1)/N);
00471
00472 Point3D ta = getDispPoint(tuva);
00473 Point3D tb = getDispPoint(tuvb);
00474 Point3D tc = getDispPoint(tuvc);
00475
00476 lastChange = 0;
00477 subPA = tb; subPB = tc; subPC = ta; uva = tuvb; uvb = tuvc; uvc = tuva;
00478 }
00479 else if(nearIs.getPrimitive() == ca) {
00480 Point3D p = nearIs.getPosition();
00481 Vec3D v = p - c->pos();
00482 Vec3D orthInSide = (dc - c->pos()).crossP(a->pos()-c->pos()).crossP(a->pos() - c->pos()).normalize();
00483 orthInSide = orthInSide * (orthInSide * faceNormal);
00484 Vec3D vp = orthInSide * (v * orthInSide);
00485 float f = fabs(vp.norm());
00486 Point3D cAl = c->pos() + (dc - c->pos()) * f;
00487 Point3D aAl = a->pos() + (da - a->pos()) * f;
00488 float x = (aAl - cAl).norm();
00489 float y = (p - cAl).norm();
00490 float ratio = y / x;
00491
00492
00493
00494
00495 float alpha = ratio;
00496 float beta = 0;
00497 float gamma = 1 - ratio;
00498
00499
00500 i = floor(alpha * N);
00501 j = floor(beta * N);
00502 k = floor(gamma * N);
00503
00504
00505 Point2D tuva = Point2D(j/N,k/N);
00506 Point2D tuvb = Point2D((j+1)/N,k/N);
00507 Point2D tuvc = Point2D(j/N,(k+1)/N);
00508
00509 Point3D ta = getDispPoint(tuva);
00510 Point3D tb = getDispPoint(tuvb);
00511 Point3D tc = getDispPoint(tuvc);
00512
00513 lastChange = 2;
00514 subPA = tc; subPB = ta; subPC = tb; uva = tuvc; uvb = tuva; uvc = tuvb;
00515 }
00516 }
00517
00518 if (!(i+j+k == N-1 || i+j+k == N-2)) {
00519 std::cout << "omfg!!! i=" << i << " j=" << j << " k=" << k << " N=" << N << std::endl;
00520 }
00521
00522 if (false) {
00523 if (i+j+k == N-1) {
00524 Intersection is = nearIs;
00525 is.setPrimitive(this);
00526 is.setSNormalL(Vec3D(1,0,0));
00527 return is;
00528 }
00529 if (i+j+k == N-2) {
00530 Intersection is = nearIs;
00531 is.setPrimitive(this);
00532 is.setSNormalL(Vec3D(0,1,0));
00533 return is;
00534 }
00535 }
00536
00537
00538
00539
00540
00541
00542
00543
00544
00545
00546
00547
00548
00549
00550
00551
00552
00553
00554
00555
00556
00557
00558
00559
00560
00561
00562
00563
00564
00565
00566
00567
00568
00569
00570
00571
00572
00573
00574
00575
00576
00577
00578
00579
00580
00581
00582
00583
00584
00585
00586
00587
00588
00589
00590
00591
00592
00593
00594
00595
00596
00597
00598
00599
00600
00601
00602
00603
00604
00605
00606
00607
00608
00609
00610
00611
00612
00613
00614
00615
00616
00617
00618
00619
00620
00621
00622
00623
00624
00625 if(true) {
00626 for (i = 0; i < N; i++) {
00627 for (j = 0; j < N; j++) {
00628 for (k = 0; k < N; k++) {
00629 if (i+j+k == N-1) {
00630
00631 Point2D uv1 = Point2D(j/N,k/N);
00632 Point2D uv2 = Point2D((j+1)/N,k/N);
00633 Point2D uv3 = Point2D(j/N,(k+1)/N);
00634
00635 Point3D po1 = getDispPoint(uv1);
00636 Point3D po2 = getDispPoint(uv2);
00637 Point3D po3 = getDispPoint(uv3);
00638
00639 Vec3D sno = (po2 - po1).crossP(po3 - po1).normalize();
00640
00641 Triangle t = Triangle(po1,po2,po3,sno,parent);
00642
00643 Intersection is = t.intersect(ray);
00644
00645 if(is.isValid()) {
00646 is.setPrimitive(this);
00647 is.setGNormalL(sno);
00648 is.setSNormalL(sno);
00649 return is;
00650 }
00651 }
00652
00653 if (i+j+k == N-2) {
00654
00655 Point2D uv1 = Point2D(j/N,(k+1)/N);
00656 Point2D uv2 = Point2D((j+1)/N,k/N);
00657 Point2D uv3 = Point2D((j+1)/N,(k+1)/N);
00658
00659 Point3D po1 = getDispPoint(uv1);
00660 Point3D po2 = getDispPoint(uv2);
00661 Point3D po3 = getDispPoint(uv3);
00662
00663 Vec3D sno = (po2 - po1).crossP(po3 - po1).normalize();
00664
00665 Triangle t = Triangle(po1,po2,po3,sno,parent);
00666
00667 Intersection is = t.intersect(ray);
00668
00669 if(is.isValid()) {
00670 is.setPrimitive(this);
00671 is.setGNormalL(sno);
00672 is.setSNormalL(sno);
00673 return is;
00674 }
00675 }
00676 }
00677 }
00678 }
00679 return Intersection();
00680 }
00681
00682
00683
00684
00685
00686
00687
00688
00689
00690 subNC = getDispNormal(uvc);
00691
00692
00693
00694 float delta = 1 / N;
00695
00696
00697
00698 while(true) {
00699
00700
00701
00702 Vec3D subNormal = (subPB - subPA).crossP(subPC - subPA).normalize();
00703 Triangle subTri(subPA, subPB, subPC, subNormal, parent);
00704
00705 Intersection subIs = subTri.intersect(ray);
00706 if (subIs.isValid()) {
00707
00708
00709
00710
00711
00712 subIs.setPrimitive(this);
00713 subIs.setGNormalL(subNormal);
00714
00715 subIs.setSNormalL(subNormal);
00716
00717
00718 return subIs;
00719 }
00720
00721 if (i == iStop && j == jStop && k == kStop) {
00722
00723 return Intersection();
00724 }
00725 rightOfC = ((subNC.crossP(ray.org() - subPC)) * ray.dir() < 0);
00726 if(rightOfC) {
00727 subPA = subPC; uva = uvc;
00728 }
00729 else {
00730 subPB = subPC; uvb = uvc;
00731 }
00732
00733 lastChange = (lastChange + (rightOfC ? 1 : 5)) % 6;
00734
00735 if(lastChange == 3 ) {
00736 if (--i < 0){
00737
00738 return Intersection();
00739 }
00740 uvc = Point2D((j+1)*delta, (k+1)*delta);
00741 }
00742 else if(lastChange == 0 ) {
00743 if (++i >= N ) {
00744
00745 return Intersection();
00746 }
00747 uvc = Point2D( j*delta, k*delta);
00748 }
00749 else if(lastChange == 1 ) {
00750 if (--j < 0) {
00751
00752 return Intersection();
00753 }
00754 uvc = Point2D( j*delta, (k+1)*delta);
00755 }
00756 else if(lastChange == 4 ) {
00757 if (++j >= N ) {
00758
00759 return Intersection();
00760 }
00761 uvc = Point2D( (j+1)*delta, k*delta);
00762 }
00763 else if(lastChange == 5 ) {
00764 if (--k < 0) {
00765
00766 return Intersection();
00767 }
00768 uvc = Point2D( (j+1)*delta, k*delta);
00769 }
00770 else if(lastChange == 2 ) {
00771 if (++k >= N ) {
00772
00773 return Intersection();
00774 }
00775 uvc = Point2D( j*delta, (k+1)*delta);
00776 }
00777 subPC = getDispPoint(uvc);
00778 subNC = getDispNormal(uvc);
00779 }
00780
00781 }
00782
00783 Point3D DisplacedTriangle::getDispPoint(float beta, float gamma) const
00784 {
00785 Point3D lp = getPoint(beta,gamma);
00786 return lp + ((upper->getPoint(beta,gamma)-lp).normalize()*parent->getMaxDispl()*parent->getDisplMap()->getColor(getUV(beta,gamma)).getLuminance());
00787 }
00788
00789 Vec3D DisplacedTriangle::getDispNormal(float beta, float gamma) const
00790 {
00791 Point3D lp = getPoint(beta,gamma);
00792 return (upper->getPoint(beta,gamma)-lp).normalize();
00793 }
00794
00795 Point3D DisplacedTriangle::getDispPoint(const Point2D& p) const
00796 {
00797 float beta = p[0];
00798 float gamma = p[1];
00799 return getDispPoint(beta,gamma);
00800 }
00801
00802 Vec3D DisplacedTriangle::getDispNormal(const Point2D& p) const
00803 {
00804 float beta = p[0];
00805 float gamma = p[1];
00806 return getDispNormal(beta,gamma);
00807 }
00808
00809 }