00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015 #ifndef __UT_Matrix3_h__
00016 #define __UT_Matrix3_h__
00017
00018 #include "UT_API.h"
00019 #include <iostream.h>
00020 #include "UT_Assert.h"
00021 #include "UT_Axis.h"
00022 #include "UT_Math.h"
00023
00024 class UT_Matrix3;
00025 class UT_Matrix4;
00026 class UT_DMatrix3;
00027 class UT_DMatrix4;
00028 class UT_XformOrder;
00029 class UT_Quaternion;
00030 class UT_Vector2;
00031 class UT_Vector3;
00032 class UT_IStream;
00033
00034
00035 UT_API UT_Matrix3 operator+(const UT_Matrix3 &m1, const UT_Matrix3 &m2);
00036 UT_API UT_Matrix3 operator-(const UT_Matrix3 &m1, const UT_Matrix3 &m2);
00037 UT_API UT_Matrix3 operator*(const UT_Matrix3 &m1, const UT_Matrix3 &m2);
00038 UT_API UT_Matrix3 operator+(const UT_Matrix3 &m, const UT_Vector3 &v);
00039 inline UT_Matrix3 operator+(const UT_Vector3 &v, const UT_Matrix3 &m);
00040 UT_API UT_Matrix3 operator-(const UT_Matrix3 &m, const UT_Vector3 &v);
00041 UT_API UT_Matrix3 operator-(const UT_Vector3 &v, const UT_Matrix3 &m);
00042 UT_API UT_Matrix3 operator+(const UT_Matrix3 &mat, fpreal sc);
00043 inline UT_Matrix3 operator-(const UT_Matrix3 &mat, fpreal sc);
00044 UT_API UT_Matrix3 operator*(const UT_Matrix3 &mat, fpreal sc);
00045 inline UT_Matrix3 operator/(const UT_Matrix3 &mat, fpreal sc);
00046 inline UT_Matrix3 operator+(fpreal sc, const UT_Matrix3 &mat);
00047 UT_API UT_Matrix3 operator-(fpreal sc, const UT_Matrix3 &mat);
00048 inline UT_Matrix3 operator*(fpreal sc, const UT_Matrix3 &mat);
00049 UT_API UT_Matrix3 operator/(fpreal sc, const UT_Matrix3 &mat);
00050
00051
00052
00053
00054
00055
00056
00057
00058 class UT_API UT_Matrix3
00059 {
00060 public:
00061
00062 UT_Matrix3()
00063 {
00064 UT_ASSERT_COMPILETIME(sizeof(UT_Matrix3) == 9 * sizeof(float));
00065 }
00066
00067 explicit UT_Matrix3(fpreal val)
00068 {
00069 matx[0][0] = val; matx[0][1] = 0; matx[0][2] = 0;
00070 matx[1][0] = 0; matx[1][1] = val; matx[1][2] = 0;
00071 matx[2][0] = 0; matx[2][1] = 0; matx[2][2] = val;
00072 }
00073
00074
00075 explicit UT_Matrix3(const fpreal32 m[3][3])
00076 {
00077 matx[0][0]=m[0][0]; matx[0][1]=m[0][1]; matx[0][2]=m[0][2];
00078 matx[1][0]=m[1][0]; matx[1][1]=m[1][1]; matx[1][2]=m[1][2];
00079 matx[2][0]=m[2][0]; matx[2][1]=m[2][1]; matx[2][2]=m[2][2];
00080 }
00081 explicit UT_Matrix3(const fpreal64 m[3][3])
00082 {
00083 matx[0][0]=m[0][0]; matx[0][1]=m[0][1]; matx[0][2]=m[0][2];
00084 matx[1][0]=m[1][0]; matx[1][1]=m[1][1]; matx[1][2]=m[1][2];
00085 matx[2][0]=m[2][0]; matx[2][1]=m[2][1]; matx[2][2]=m[2][2];
00086 }
00087
00088
00089
00090
00091 UT_Matrix3(fpreal32 val00, fpreal32 val01, fpreal32 val02,
00092 fpreal32 val10, fpreal32 val11, fpreal32 val12,
00093 fpreal32 val20, fpreal32 val21, fpreal32 val22)
00094 {
00095 matx[0][0] = val00; matx[0][1] = val01; matx[0][2] = val02;
00096 matx[1][0] = val10; matx[1][1] = val11; matx[1][2] = val12;
00097 matx[2][0] = val20; matx[2][1] = val21; matx[2][2] = val22;
00098 }
00099
00100
00101 explicit UT_Matrix3(const UT_Matrix4 &m);
00102
00103
00104
00105
00106
00107
00108
00109 UT_Matrix3 &operator=(const UT_Matrix4 &m);
00110 UT_Matrix3 &operator=(const UT_DMatrix4 &m);
00111
00112 UT_Matrix3 &operator=(const UT_DMatrix3 &m);
00113
00114 UT_Matrix3 operator-() const
00115 {
00116 return UT_Matrix3(-matx[0][0], -matx[0][1], -matx[0][2],
00117 -matx[1][0], -matx[1][1], -matx[1][2],
00118 -matx[2][0], -matx[2][1], -matx[2][2]);
00119 }
00120
00121
00122 inline void addScaledMat(fpreal k, const UT_Matrix3 &m)
00123 {
00124 matx[0][0]+=k*m.matx[0][0];
00125 matx[0][1]+=k*m.matx[0][1];
00126 matx[0][2]+=k*m.matx[0][2];
00127
00128 matx[1][0]+=k*m.matx[1][0];
00129 matx[1][1]+=k*m.matx[1][1];
00130 matx[1][2]+=k*m.matx[1][2];
00131
00132 matx[2][0]+=k*m.matx[2][0];
00133 matx[2][1]+=k*m.matx[2][1];
00134 matx[2][2]+=k*m.matx[2][2];
00135 }
00136 inline UT_Matrix3 &operator+=(const UT_Matrix3 &m)
00137 {
00138 matx[0][0]+=m.matx[0][0];
00139 matx[0][1]+=m.matx[0][1];
00140 matx[0][2]+=m.matx[0][2];
00141
00142 matx[1][0]+=m.matx[1][0];
00143 matx[1][1]+=m.matx[1][1];
00144 matx[1][2]+=m.matx[1][2];
00145
00146 matx[2][0]+=m.matx[2][0];
00147 matx[2][1]+=m.matx[2][1];
00148 matx[2][2]+=m.matx[2][2];
00149 return *this;
00150 }
00151 inline UT_Matrix3 &operator-=(const UT_Matrix3 &m)
00152 {
00153 matx[0][0]-=m.matx[0][0];
00154 matx[0][1]-=m.matx[0][1];
00155 matx[0][2]-=m.matx[0][2];
00156
00157 matx[1][0]-=m.matx[1][0];
00158 matx[1][1]-=m.matx[1][1];
00159 matx[1][2]-=m.matx[1][2];
00160
00161 matx[2][0]-=m.matx[2][0];
00162 matx[2][1]-=m.matx[2][1];
00163 matx[2][2]-=m.matx[2][2];
00164 return *this;
00165 }
00166 UT_Matrix3 &operator*=(const UT_Matrix3 &m);
00167
00168 void multiply3(const UT_Matrix4 &m);
00169 void multiply3(const UT_DMatrix4 &m);
00170
00171 unsigned operator==(const UT_Matrix3 &m) const;
00172 unsigned operator!=(const UT_Matrix3 &m) const
00173 {
00174 return !(*this == m);
00175 }
00176
00177
00178 UT_Matrix3 &operator= (fpreal val)
00179 {
00180 matx[0][0] = val; matx[0][1] = 0; matx[0][2] = 0;
00181 matx[1][0] = 0; matx[1][1] = val; matx[1][2] = 0;
00182 matx[2][0] = 0; matx[2][1] = 0; matx[2][2] = val;
00183 return *this;
00184 }
00185 inline UT_Matrix3 &operator*=(fpreal scalar)
00186 {
00187 matx[0][0]*=scalar; matx[0][1]*=scalar; matx[0][2]*=scalar;
00188 matx[1][0]*=scalar; matx[1][1]*=scalar; matx[1][2]*=scalar;
00189 matx[2][0]*=scalar; matx[2][1]*=scalar; matx[2][2]*=scalar;
00190 return *this;
00191 }
00192 inline UT_Matrix3 &operator/=(fpreal scalar)
00193 {
00194 return operator*=( 1.0f/scalar );
00195 }
00196
00197
00198 inline UT_Matrix3 &operator= (const UT_Vector3 &vec);
00199 inline UT_Matrix3 &operator+=(const UT_Vector3 &vec);
00200 inline UT_Matrix3 &operator-=(const UT_Vector3 &vec);
00201
00202
00203
00204 inline void outerproductUpdate(fpreal b,
00205 const UT_Vector3 &v1,
00206 const UT_Vector3 &v2);
00207
00208
00209
00210
00211
00212
00213
00214 void getBasis();
00215
00216
00217
00218
00219 void arbitrary180rot();
00220
00221
00222
00223
00224
00225
00226
00227
00228
00229
00230
00231
00232 static UT_Matrix3 dihedral(UT_Vector3 &a, UT_Vector3 &b,
00233 UT_Vector3 &c,int norm=1);
00234 int dihedral(UT_Vector3 &a, UT_Vector3 &b,
00235 int norm=1);
00236
00237
00238
00239
00240
00241
00242
00243
00244
00245
00246 void lookat(const UT_Vector3 &from, const UT_Vector3 &to,
00247 fpreal roll = 0);
00248 void lookat(const UT_Vector3 &from, const UT_Vector3 &to,
00249 const UT_Vector3 &up);
00250
00251
00252
00253
00254
00255
00256
00257
00258
00259 int orient(UT_Vector3 &dir, UT_Vector3 &up, int norm=1);
00260
00261
00262
00263
00264
00265
00266
00267
00268
00269
00270
00271 void orient(const UT_Vector3& v,
00272 fpreal pscale, const UT_Vector3 *s3,
00273 const UT_Vector3* up,
00274 const UT_Quaternion* q);
00275
00276
00277
00278
00279 fpreal coFactor(int k, int l) const;
00280
00281 fpreal determinant() const
00282 {
00283 return(matx[0][0]*
00284 (matx[1][1]*matx[2][2]-matx[1][2]*matx[2][1]) +
00285 matx[0][1]*
00286 (matx[1][2]*matx[2][0]-matx[1][0]*matx[2][2]) +
00287 matx[0][2]*
00288 (matx[1][0]*matx[2][1]-matx[1][1]*matx[2][0]) );
00289
00290 }
00291 fpreal trace() const
00292 { return matx[0][0] + matx[1][1] + matx[2][2]; }
00293
00294
00295
00296 int eigenvalues(UT_Vector3 &r, UT_Vector3 &i) const;
00297
00298
00299 int invert();
00300
00301
00302 int invert(UT_Matrix3 &m)const;
00303 int invertKramer();
00304 int invertKramer(UT_Matrix3 &m)const;
00305
00306
00307 void transpose(void)
00308 {
00309 fpreal tmp;
00310 tmp=matx[0][1]; matx[0][1]=matx[1][0]; matx[1][0]=tmp;
00311 tmp=matx[0][2]; matx[0][2]=matx[2][0]; matx[2][0]=tmp;
00312 tmp=matx[1][2]; matx[1][2]=matx[2][1]; matx[2][1]=tmp;
00313 }
00314 UT_Matrix3 transpose(void) const;
00315
00316
00317 unsigned isEqual( const UT_Matrix3 &m,
00318 fpreal tolerance=UT_FTOLERANCE ) const
00319 {
00320 return (&m == this) ? 1U : (
00321 UTisEqual( matx[0][0], m.matx[0][0], tolerance ) &&
00322 UTisEqual( matx[0][1], m.matx[0][1], tolerance ) &&
00323 UTisEqual( matx[0][2], m.matx[0][2], tolerance ) &&
00324
00325 UTisEqual( matx[1][0], m.matx[1][0], tolerance ) &&
00326 UTisEqual( matx[1][1], m.matx[1][1], tolerance ) &&
00327 UTisEqual( matx[1][2], m.matx[1][2], tolerance ) &&
00328
00329 UTisEqual( matx[2][0], m.matx[2][0], tolerance ) &&
00330 UTisEqual( matx[2][1], m.matx[2][1], tolerance ) &&
00331 UTisEqual( matx[2][2], m.matx[2][2], tolerance ) );
00332 }
00333
00334 bool isSymmetric(fpreal tolerance = UT_FTOLERANCE) const;
00335
00336
00337
00338
00339
00340
00341 void rotate(UT_Vector3 &axis, fpreal theta, int norm=1);
00342 UT_Matrix3 rotate(UT_Vector3 &axis, fpreal theta, int norm=1) const;
00343 static UT_Matrix3 rotationMat(UT_Vector3 &axis, fpreal theta, int norm=1);
00344 void rotate(UT_Axis3::axis a, fpreal theta);
00345 UT_Matrix3 rotate(UT_Axis3::axis a, fpreal theta) const;
00346 static UT_Matrix3 rotationMat(UT_Axis3::axis a, fpreal theta);
00347
00348
00349 void prerotate(UT_Vector3 &axis, fpreal theta, int norm=1);
00350 UT_Matrix3 prerotate(UT_Vector3 &axis, fpreal theta, int norm=1) const;
00351 void prerotate(UT_Axis3::axis a, fpreal theta);
00352 UT_Matrix3 prerotate(UT_Axis3::axis a, fpreal theta) const;
00353
00354
00355
00356 void prerotate(fpreal rx, fpreal ry, fpreal rz,
00357 const UT_XformOrder &order);
00358 UT_Matrix3 prerotate(fpreal rx, fpreal ry, fpreal rz,
00359 const UT_XformOrder &order) const;
00360
00361
00362
00363
00364 void rotate(fpreal rx, fpreal ry, fpreal rz,
00365 const UT_XformOrder &ord);
00366 UT_Matrix3 rotate(fpreal rx, fpreal ry, fpreal rz,
00367 const UT_XformOrder &ord) const;
00368
00369
00370 void scale(fpreal sx, fpreal sy, fpreal sz)
00371 {
00372 matx[0][0] *= sx; matx[0][1] *= sy; matx[0][2] *= sz;
00373 matx[1][0] *= sx; matx[1][1] *= sy; matx[1][2] *= sz;
00374 matx[2][0] *= sx; matx[2][1] *= sy; matx[2][2] *= sz;
00375 }
00376 UT_Matrix3 scale(fpreal sx, fpreal sy, fpreal sz) const;
00377
00378
00379 void prescale(fpreal sx, fpreal sy, fpreal sz)
00380 {
00381 matx[0][0] *= sx; matx[1][0] *= sy; matx[2][0] *= sz;
00382 matx[0][1] *= sx; matx[1][1] *= sy; matx[2][1] *= sz;
00383 matx[0][2] *= sx; matx[1][2] *= sy; matx[2][2] *= sz;
00384 }
00385 UT_Matrix3 prescale(fpreal sx, fpreal sy, fpreal sz) const;
00386
00387
00388 void translate(fpreal dx, fpreal dy)
00389 {
00390 matx[0][0] += matx[0][2] * dx;
00391 matx[0][1] += matx[0][2] * dy;
00392 matx[1][0] += matx[1][2] * dx;
00393 matx[1][1] += matx[1][2] * dy;
00394 matx[2][0] += matx[2][2] * dx;
00395 matx[2][1] += matx[2][2] * dy;
00396 }
00397 UT_Matrix3 translate(fpreal dx, fpreal dy) const;
00398
00399
00400 void pretranslate(fpreal dx, fpreal dy)
00401 {
00402 matx[2][0] += matx[0][0] * dx + matx[1][0] * dy;
00403 matx[2][1] += matx[0][1] * dx + matx[1][1] * dy;
00404 matx[2][2] += matx[0][2] * dx + matx[1][2] * dy;
00405 }
00406 UT_Matrix3 pretranslate(fpreal dx, fpreal dy) const;
00407
00408
00409
00410
00411
00412
00413 int crack(UT_Vector3 &rvec, const UT_XformOrder &order,
00414 int remove_scales=1);
00415 int crack(UT_Vector3 &rvec, const UT_XformOrder &order,
00416 int remove_scales=1) const;
00417 int crack2D(float &r) const;
00418
00419
00420
00421
00422
00423 void conditionRotate(UT_Vector3 *scales = 0);
00424
00425
00426
00427
00428 void extractScales(UT_Vector3 &scales, UT_Vector3 *shears=0);
00429
00430
00431
00432
00433
00434 void extractScales2D(UT_Vector2 &scales, float *shears=0);
00435
00436
00437
00438 void shearXY(fpreal val);
00439 void shearXZ(fpreal val);
00440 void shearYZ(fpreal val);
00441
00442
00443 void shear(fpreal s_xy, fpreal s_xz, fpreal s_yz)
00444 {
00445 matx[0][0] += matx[0][1]*s_xy + matx[0][2]*s_xz;
00446 matx[0][1] += matx[0][2]*s_yz;
00447
00448 matx[1][0] += matx[1][1]*s_xy + matx[1][2]*s_xz;
00449 matx[1][1] += matx[1][2]*s_yz;
00450
00451 matx[2][0] += matx[2][1]*s_xy + matx[2][2]*s_xz;
00452 matx[2][1] += matx[2][2]*s_yz;
00453 }
00454
00455
00456
00457
00458 int solve(fpreal cx, fpreal cy, fpreal cz,
00459 UT_Vector3 &result) const;
00460
00461
00462
00463
00464
00465
00466
00467 void changeSpace(UT_Vector3 &iSrc, UT_Vector3 &jSrc,
00468 UT_Vector3 &iDest,UT_Vector3 &jDest,
00469 int norm=1);
00470 UT_Matrix3 changeSpace(UT_Vector3 &iSrc, UT_Vector3 &jSrc,
00471 UT_Vector3 &iDest,UT_Vector3 &jDest,
00472 int norm=1) const;
00473
00474
00475
00476
00477
00478
00479
00480
00481
00482 void xform(const UT_XformOrder &order,
00483 fpreal tx=0.0f, fpreal ty=0.0f, fpreal rz=0.0f,
00484 fpreal sx=1.0f, fpreal sy=1.0f,fpreal px=0.0f,fpreal py=0.0f,
00485 int reverse=0);
00486 UT_Matrix3 xform(const UT_XformOrder &order,
00487 fpreal tx=0.0f, fpreal ty=0.0f, fpreal rz=0.0f,
00488 fpreal sx=1.0f, fpreal sy=1.0f,fpreal px=0.0f,fpreal py=0.0f,
00489 int reverse=0) const;
00490
00491
00492 void xform(const UT_XformOrder &order,
00493 fpreal tx, fpreal ty, fpreal rz,
00494 fpreal sx, fpreal sy, fpreal s_xy,
00495 fpreal px, fpreal py,
00496 int reverse=0);
00497
00498
00499
00500
00501
00502 void stretch(UT_Vector3 &v, fpreal amount, int norm=1);
00503 UT_Matrix3 stretch(UT_Vector3 &v, fpreal amount, int norm=1) const;
00504
00505
00506
00507
00508 int isNormalized() const;
00509
00510
00511 fpreal dot(unsigned i, unsigned j) const
00512 {
00513 return (i <= 2 && j <= 2) ?
00514 matx[i][0]*matx[j][0] + matx[i][1]*matx[j][1] +
00515 matx[i][2]*matx[j][2] : (fpreal)0;
00516 }
00517
00518
00519 void identity() { *this = 1; }
00520
00521 void zero() { *this = 0; }
00522
00523 int isIdentity() const
00524 {
00525
00526 return(
00527 matx[0][0]==1.0f && matx[0][1]==0.0f &&
00528 matx[0][2]==0.0f && matx[1][0]==0.0f &&
00529 matx[1][1]==1.0f && matx[1][2]==0.0f &&
00530 matx[2][0]==0.0f && matx[2][1]==0.0f &&
00531 matx[2][2]==1.0f
00532 );
00533 }
00534
00535
00536
00537 const fpreal32 *data(void) const { return (const fpreal32 *)&matx[0][0];}
00538 fpreal32 *data(void) { return (fpreal32 *)&matx[0][0]; }
00539
00540
00541
00542
00543 inline float&operator()(unsigned row, unsigned col)
00544 {
00545 UT_ASSERT_P(row < 3 && col < 3);
00546 return matx[row][col];
00547 }
00548 inline float operator()(unsigned row, unsigned col) const
00549 {
00550 UT_ASSERT_P(row < 3 && col < 3);
00551 return matx[row][col];
00552 }
00553
00554
00555
00556
00557 float *operator()(unsigned row)
00558 {
00559 UT_ASSERT_P(row < 3);
00560 return matx[row];
00561 }
00562 const float *operator()(unsigned row) const
00563 {
00564 UT_ASSERT_P(row < 3);
00565 return matx[row];
00566 }
00567 UT_Vector3 operator[](unsigned row) const;
00568
00569
00570
00571
00572 fpreal getEuclideanNorm() const
00573 { return SYSsqrt(getEuclideanNorm2()); }
00574
00575 fpreal getEuclideanNorm2() const;
00576
00577
00578 int save(ostream &os, int binary) const;
00579 bool load(UT_IStream &is);
00580
00581 void outAsciiNoName(ostream &os) const;
00582
00583 static const UT_Matrix3 &getIdentityMatrix();
00584
00585
00586 friend ostream &operator<<(ostream &os, const UT_Matrix3 &v)
00587 {
00588 os << className() << ' ';
00589 v.outAsciiNoName(os);
00590 return os;
00591 }
00592 private:
00593
00594
00595
00596 int checkRot() const;
00597 void permute(int l0, int l1, int l2);
00598
00599 static const char *className(void);
00600
00601
00602 fpreal32 matx[3][3];
00603 };
00604
00605 #include "UT_Vector3.h"
00606
00607 inline
00608 UT_Matrix3 &UT_Matrix3::operator=(const UT_Vector3 &vec)
00609 {
00610 matx[0][0] = matx[0][1] = matx[0][2] = vec.x();
00611 matx[1][0] = matx[1][1] = matx[1][2] = vec.y();
00612 matx[2][0] = matx[2][1] = matx[2][2] = vec.z();
00613 return *this;
00614 }
00615
00616 inline
00617 UT_Matrix3 &UT_Matrix3::operator+=(const UT_Vector3 &vec)
00618 {
00619 fpreal x = vec.x(); fpreal y = vec.y(); fpreal z = vec.z();
00620 matx[0][0]+=x; matx[0][1]+=x; matx[0][2]+=x;
00621 matx[1][0]+=y; matx[1][1]+=y; matx[1][2]+=y;
00622 matx[2][0]+=z; matx[2][1]+=z; matx[2][2]+=z;
00623 return *this;
00624 }
00625
00626 inline
00627 UT_Matrix3 &UT_Matrix3::operator-=(const UT_Vector3 &vec)
00628 {
00629 fpreal x = vec.x(); fpreal y = vec.y(); fpreal z = vec.z();
00630 matx[0][0]-=x; matx[0][1]-=x; matx[0][2]-=x;
00631 matx[1][0]-=y; matx[1][1]-=y; matx[1][2]-=y;
00632 matx[2][0]-=z; matx[2][1]-=z; matx[2][2]-=z;
00633 return *this;
00634 }
00635
00636
00637
00638 inline
00639 void UT_Matrix3::outerproductUpdate(fpreal b,
00640 const UT_Vector3 &v1,
00641 const UT_Vector3 &v2)
00642 {
00643 fpreal bv1;
00644 bv1 = b * v1.x();
00645 matx[0][0]+=bv1*v2.x();
00646 matx[0][1]+=bv1*v2.y();
00647 matx[0][2]+=bv1*v2.z();
00648 bv1 = b * v1.y();
00649 matx[1][0]+=bv1*v2.x();
00650 matx[1][1]+=bv1*v2.y();
00651 matx[1][2]+=bv1*v2.z();
00652 bv1 = b * v1.z();
00653 matx[2][0]+=bv1*v2.x();
00654 matx[2][1]+=bv1*v2.y();
00655 matx[2][2]+=bv1*v2.z();
00656 }
00657
00658 inline
00659 UT_Vector3 UT_Matrix3::operator[](unsigned row) const
00660 {
00661 UT_ASSERT_P(row < 3);
00662 return UT_Vector3(matx[row]);
00663 }
00664
00665
00666
00667 inline
00668 UT_Matrix3 operator+(const UT_Vector3 &vec, const UT_Matrix3 &mat)
00669 {
00670 return mat+vec;
00671 }
00672
00673 inline
00674 UT_Matrix3 operator*(fpreal sc, const UT_Matrix3 &m1)
00675 {
00676 return m1*sc;
00677 }
00678
00679 inline
00680 UT_Matrix3 operator/(const UT_Matrix3 &m1, fpreal scalar)
00681 {
00682 return (m1 * (1.0f/scalar));
00683 }
00684
00685 #endif