00001
00002
00003
00004
00005
00006
00007
00008 #include <stdlib.h>
00009 #include <stdio.h>
00010 #include <math.h>
00011 #include <windows.h>
00012
00013 #ifdef __cplusplus
00014 extern "C" {
00015 #endif
00016
00017 #include "struct.h"
00018 #include "dstruct.h"
00019
00020 #ifdef __cplusplus
00021 }
00022 #endif
00023
00024 #include "subdiv.h"
00025
00026 #define DESELECTED 0
00027 #define SELECTED 1
00028 #define FAIL -1
00029 #define OK 1
00030
00031
00032 static HWND hParent;
00033 static HINSTANCE hThisInstance;
00034
00035
00036 #if __WATCOMC__
00037 int APIENTRY LibMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
00038 #else
00039 BOOL WINAPI DllMain(HANDLE hDLL, DWORD dwReason, LPVOID lpReserved){
00040 #endif
00041 switch (dwReason) {
00042 case DLL_PROCESS_ATTACH: {
00043 hThisInstance=(HINSTANCE)hDLL;
00044 if(hDLL == NULL)MessageBox ( GetFocus()," NULL instance",NULL, MB_OK);
00045 break;
00046 }
00047 case DLL_PROCESS_DETACH:
00048 break;
00049 }
00050 return TRUE;
00051 }
00052
00053 #if __SC__
00054 #pragma startaddress(DllMain)
00055 #endif
00056
00057 static int BuildNormals(long down_to_f, long down_to_e);
00058 static int Subdivide(long down_to_f, long down_to_e);
00059
00060 extern "C" BOOL _Xmodeler
00061 (HWND parent_window,HWND info_window,X__STRUCTURE *lpevi){
00062 lpEVI=lpevi;
00063 hParent=parent_window;
00064
00065
00066
00067 {
00068 HCURSOR hSave;
00069 if(NvertSelect == 0 || NvertSelect > 32000)return FALSE;
00070 hSave=SetCursor(LoadCursor(NULL,IDC_WAIT));
00071 OrientateSelectedFaces();
00072 Subdivide(0,0);
00073
00074 SetCursor(hSave);
00075 }
00076 return TRUE;
00077 }
00078
00079 #define VECCOPY(a,b) { b[0] = a[0]; b[1] = a[1]; b[2] = a[2]; }
00080 #define VECSUB(a,b,c) { c[0]=a[0]-b[0]; c[1]=a[1]-b[1]; c[2]=a[2]-b[2];}
00081 #define VECSUM(a,b,c) { c[0]=a[0]+b[0]; c[1]=a[1]+b[1]; c[2]=a[2]+b[2];}
00082 #define VECSCALE(a,b,c) { c[0]=(a)*b[0]; c[1]=(a)*b[1]; c[2]=(a)*b[2];}
00083 #define DOT(a,b) ( (a[0]*b[0]) + (a[1]*b[1]) + (a[2]*b[2]) )
00084 #define CROSS(v1,v2,r) { \
00085 r[0] = (v1[1]*v2[2]) - (v2[1]*v1[2]); \
00086 r[1] = (v1[2]*v2[0]) - (v1[0]*v2[2]); \
00087 r[2] = (v1[0]*v2[1]) - (v2[0]*v1[1]); \
00088 }
00089
00090 typedef struct tagVERTEXVERTEX{
00091 long vl,vr;
00092 } VERTEXVERTEX;
00093
00094 typedef struct tagFACEEXTRA{
00095 long extra,xxtra;
00096 } FACEEXTRA;
00097
00098 typedef struct tagVERTEXNORMAL{
00099 BOOL set;
00100 vector n;
00101 } VERTEXNORMAL;
00102
00103
00104 static BOOL GetFaceNormal(vertex *V0, vertex *V1, vertex *V2,
00105 vector n){
00106 vector u,v;
00107 VECSUB((double)V1->xyz,(double)V0->xyz,u)
00108 VECSUB((double)V2->xyz,(double)V0->xyz,v)
00109 CROSS(u,v,n);
00110 if(oNormalize(n) == FAIL)return FALSE;
00111 return TRUE;
00112 }
00113
00114 static void SetNewVertexPosition(vertex *Vn, long vl, long vr,
00115 VERTEXNORMAL *MainPp, long Pmax){
00116 double l,dot;
00117 vertex *V0, *V1;
00118 vector p,dp,dl;
00119 V0=(MainVp+vl);
00120 V1=(MainVp+vr);
00121 if(vl >= Pmax || vr >= Pmax || !((MainPp+vl)->set) || !((MainPp+vr)->set)){
00122 Vn->xyz[0]=(V0->xyz[0] + V1->xyz[0])/2;
00123 Vn->xyz[1]=(V0->xyz[1] + V1->xyz[1])/2;
00124 Vn->xyz[2]=(V0->xyz[2] + V1->xyz[2])/2;
00125 return;
00126 }
00127 l=sqrt((double)(V1->xyz[0] - V0->xyz[0])*(double)(V1->xyz[0] - V0->xyz[0])+
00128 (double)(V1->xyz[1] - V0->xyz[1])*(double)(V1->xyz[1] - V0->xyz[1])+
00129 (double)(V1->xyz[2] - V0->xyz[2])*(double)(V1->xyz[2] - V0->xyz[2]));
00130 VECSUM((MainPp+vl)->n,(MainPp+vr)->n,dp)
00131 VECSUB((double)V1->xyz,(double)V0->xyz,dl)
00132 oNormalize(dp);
00133 oNormalize(dl);
00134 p[0]=(double)(V0->xyz[0] + V1->xyz[0])/2;
00135 p[1]=(double)(V0->xyz[1] + V1->xyz[1])/2;
00136 p[2]=(double)(V0->xyz[2] + V1->xyz[2])/2;
00137 dot=DOT((MainPp+vl)->n,(MainPp+vr)->n);
00138 l *= (1.0-dot)*0.20710678;
00139 l *= 2;
00140 vector d,r;
00141 CROSS((MainPp+vl)->n,(MainPp+vr)->n,d)
00142 CROSS(dl,d,r)
00143 if(DOT(r,(MainPp+vl)->n) < 0.0)l *= -1;
00144 Vn->xyz[0]=(long)(p[0]+l*dp[0]);
00145 Vn->xyz[1]=(long)(p[1]+l*dp[1]);
00146 Vn->xyz[2]=(long)(p[2]+l*dp[2]);
00147 return;
00148 }
00149
00150
00151
00152
00153
00154 static int Subdivide(long down_to_f, long down_to_e){
00155 vector face_normal;
00156 face *fp;
00157 edge *ep;
00158 vertex *vp,*V0,*V1,*V2;
00159 long i,j,vl,vr,id,nf=0,ne=0,n,Nedge1,Nface1,Nv1,Nnormals;
00160 VERTEXVERTEX *vlist=NULL;
00161 FACEEXTRA *MainLp=NULL,*lp;
00162 VERTEXNORMAL *MainPp=NULL,*pp;
00163 HCURSOR hSave;
00164
00165 if(down_to_f < Nface){
00166 if((MainLp=(FACEEXTRA *)X__Malloc(Nface*sizeof(FACEEXTRA))) == NULL){
00167 return FAIL;
00168 }
00169 Nnormals=Nvert;
00170 if((MainPp=(VERTEXNORMAL *)X__Malloc(Nvert*sizeof(VERTEXNORMAL))) == NULL){
00171 if(MainLp != NULL)X__Free(MainLp);
00172 return FAIL;
00173 }
00174 for(i=0,pp=MainPp;i<Nnormals;i++,pp++){
00175 pp->set=FALSE;
00176 pp->n[0] = pp->n[1] = pp->n[2] = 0.0;
00177 }
00178 fp=(MainFp+down_to_f); lp=(MainLp+down_to_f); nf=0;
00179 for(i=down_to_f;i<Nface;i++){
00180 lp->extra = -1;
00181 lp->xxtra = -1;
00182 V0=(MainVp+fp->V[0]); V1=(MainVp+fp->V[1]); V2=(MainVp+fp->V[2]);
00183 if((V0->status == SELECTED && V1->status == SELECTED) ||
00184 (V1->status == SELECTED && V2->status == SELECTED) ||
00185 (V2->status == SELECTED && V0->status == SELECTED)){
00186 if(GetFaceNormal(V0,V1,V2,face_normal)){
00187 VECSUM((MainPp+fp->V[0])->n,face_normal,(MainPp+fp->V[0])->n)
00188 VECSUM((MainPp+fp->V[1])->n,face_normal,(MainPp+fp->V[1])->n)
00189 VECSUM((MainPp+fp->V[2])->n,face_normal,(MainPp+fp->V[2])->n)
00190 (MainPp+fp->V[0])->set=TRUE;
00191 (MainPp+fp->V[1])->set=TRUE;
00192 (MainPp+fp->V[2])->set=TRUE;
00193 }
00194 nf++;
00195 }
00196 fp++; lp++;
00197 }
00198 }
00199 for(i=0,pp=MainPp;i<Nnormals;i++,pp++){
00200 if(pp->set){
00201 if(oNormalize(pp->n) == FAIL)pp->set=FALSE;
00202 }
00203 }
00204 for(ep=(MainEp+down_to_e),ne=0,i=down_to_e;i<Nedge;i++){
00205 if((MainVp+ep->V[0])->status == SELECTED &&
00206 (MainVp+ep->V[1])->status == SELECTED)ne++;
00207 ep++;
00208 }
00209 if(ne == 0){
00210 if(MainLp != NULL)X__Free(MainLp);
00211 if(MainPp != NULL)X__Free(MainPp);
00212 return FAIL;
00213 }
00214
00215 if((vlist=(VERTEXVERTEX *)X__Malloc(ne*sizeof(VERTEXVERTEX))) == NULL){
00216 if(MainPp != NULL)X__Free(MainPp);
00217 if(MainLp != NULL)X__Free(MainLp);
00218 return FAIL;
00219 }
00220 if(!UpdateVertexHeap(Nvert+ne))goto EP1;
00221 if(!UpdateEdgeHeap(Nedge+ne+nf*3))goto EP1;
00222 if(!UpdateFaceHeap(Nface+nf*3))goto EP1;
00223 Nface1=Nface; Nedge1=Nedge;
00224 ep=(MainEp+down_to_e); n=0;
00225 for(i=down_to_e;i<Nedge1;i++){
00226 vl=ep->V[0]; V0=(MainVp+vl); vr=ep->V[1]; V1=(MainVp+vr);
00227 if(V0->status == SELECTED && V1->status == SELECTED){
00228 CreateVertex(); Nv1=Nvert-1;
00229 vlist[n].vl=vl; vlist[n].vr=vr; (MainVp+Nv1)->id=n; n++;
00230 SetNewVertexPosition((MainVp+Nv1),vl,vr,MainPp,Nnormals);
00231 CreateEdge(Nv1,ep->V[1]);
00232 ep->V[1]=Nv1;
00233 if(down_to_f < Nface1){
00234 fp=(MainFp+down_to_f); lp=(MainLp+down_to_f);
00235 for(j=down_to_f;j<Nface1;j++){
00236 id=0;
00237 if ((fp->V[0] == vl && fp->V[1] == vr) ||
00238 (fp->V[0] == vr && fp->V[1] == vl) )id=1;
00239 else if((fp->V[1] == vl && fp->V[2] == vr) ||
00240 (fp->V[1] == vr && fp->V[2] == vl) )id=2;
00241 else if((fp->V[2] == vl && fp->V[0] == vr) ||
00242 (fp->V[2] == vr && fp->V[0] == vl) )id=3;
00243 if(id != 0){
00244 if(lp->extra < 0)lp->extra=Nv1;
00245 else{
00246 if(lp->xxtra < 0)lp->xxtra=Nv1;
00247 else{
00248 CreateEdge(Nv1,lp->extra);
00249 CreateEdge(Nv1,lp->xxtra);
00250 CreateEdge(lp->extra,lp->xxtra);
00251 if (id == 1){
00252 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00253 fp->V[2],lp->xxtra,lp->extra))
00254 CreateFace(fp->V[2],lp->xxtra,lp->extra);
00255 else
00256 CreateFace(fp->V[2],lp->extra,lp->xxtra);
00257 CopyFaceProp(fp,(MainFp+Nface-1));
00258 if(vlist[(MainVp+lp->extra)->id].vl == fp->V[0] ||
00259 vlist[(MainVp+lp->extra)->id].vr == fp->V[0]){
00260 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00261 fp->V[0],Nv1,lp->extra))
00262 CreateFace(fp->V[0],Nv1,lp->extra);
00263 else
00264 CreateFace(fp->V[0],lp->extra,Nv1);
00265 CopyFaceProp(fp,(MainFp+Nface-1));
00266 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00267 fp->V[1],Nv1,lp->xxtra))
00268 CreateFace(fp->V[1],Nv1,lp->xxtra);
00269 else
00270 CreateFace(fp->V[1],lp->xxtra,Nv1);
00271 CopyFaceProp(fp,(MainFp+Nface-1));
00272 }
00273 else{
00274 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00275 fp->V[1],Nv1,lp->extra))
00276 CreateFace(fp->V[1],Nv1,lp->extra);
00277 else
00278 CreateFace(fp->V[1],lp->extra,Nv1);
00279 CopyFaceProp(fp,(MainFp+Nface-1));
00280 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00281 fp->V[0],Nv1,lp->xxtra))
00282 CreateFace(fp->V[0],Nv1,lp->xxtra);
00283 else
00284 CreateFace(fp->V[0],lp->xxtra,Nv1);
00285 CopyFaceProp(fp,(MainFp+Nface-1));
00286 }
00287 }
00288 else if(id == 2){
00289 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00290 fp->V[0],lp->xxtra,lp->extra))
00291 CreateFace(fp->V[0],lp->xxtra,lp->extra);
00292 else
00293 CreateFace(fp->V[0],lp->extra,lp->xxtra);
00294 CopyFaceProp(fp,(MainFp+Nface-1));
00295 if(vlist[(MainVp+lp->extra)->id].vl == fp->V[1] ||
00296 vlist[(MainVp+lp->extra)->id].vr == fp->V[1]){
00297 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00298 fp->V[1],Nv1,lp->extra))
00299 CreateFace(fp->V[1],Nv1,lp->extra);
00300 else
00301 CreateFace(fp->V[1],lp->extra,Nv1);
00302 CopyFaceProp(fp,(MainFp+Nface-1));
00303 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00304 fp->V[2],Nv1,lp->xxtra))
00305 CreateFace(fp->V[2],Nv1,lp->xxtra);
00306 else
00307 CreateFace(fp->V[2],lp->xxtra,Nv1);
00308 CopyFaceProp(fp,(MainFp+Nface-1));
00309 }
00310 else{
00311 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00312 fp->V[2],Nv1,lp->extra))
00313 CreateFace(fp->V[2],Nv1,lp->extra);
00314 else
00315 CreateFace(fp->V[2],lp->extra,Nv1);
00316 CopyFaceProp(fp,(MainFp+Nface-1));
00317 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00318 fp->V[1],Nv1,lp->xxtra))
00319 CreateFace(fp->V[1],Nv1,lp->xxtra);
00320 else
00321 CreateFace(fp->V[1],lp->xxtra,Nv1);
00322 CopyFaceProp(fp,(MainFp+Nface-1));
00323 }
00324 }
00325 else if(id == 3){
00326 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00327 fp->V[1],lp->xxtra,lp->extra))
00328 CreateFace(fp->V[1],lp->xxtra,lp->extra);
00329 else
00330 CreateFace(fp->V[1],lp->extra,lp->xxtra);
00331 CopyFaceProp(fp,(MainFp+Nface-1));
00332 if(vlist[(MainVp+lp->extra)->id].vl == fp->V[2] ||
00333 vlist[(MainVp+lp->extra)->id].vr == fp->V[2]){
00334 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00335 fp->V[2],Nv1,lp->extra))
00336 CreateFace(fp->V[2],Nv1,lp->extra);
00337 else
00338 CreateFace(fp->V[2],lp->extra,Nv1);
00339 CopyFaceProp(fp,(MainFp+Nface-1));
00340 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00341 fp->V[0],Nv1,lp->xxtra))
00342 CreateFace(fp->V[0],Nv1,lp->xxtra);
00343 else
00344 CreateFace(fp->V[0],lp->xxtra,Nv1);
00345 CopyFaceProp(fp,(MainFp+Nface-1));
00346 }
00347 else{
00348 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00349 fp->V[0],Nv1,lp->extra))
00350 CreateFace(fp->V[0],Nv1,lp->extra);
00351 else
00352 CreateFace(fp->V[0],lp->extra,Nv1);
00353 CopyFaceProp(fp,(MainFp+Nface-1));
00354 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00355 fp->V[2],Nv1,lp->xxtra))
00356 CreateFace(fp->V[2],Nv1,lp->xxtra);
00357 else
00358 CreateFace(fp->V[2],lp->xxtra,Nv1);
00359 CopyFaceProp(fp,(MainFp+Nface-1));
00360 }
00361 }
00362 if(IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00363 lp->xxtra,lp->extra,Nv1)){
00364 fp->V[0]=lp->xxtra;
00365 fp->V[1]=lp->extra;
00366 fp->V[2]=Nv1;
00367 }
00368 else{
00369 fp->V[0]=lp->xxtra;
00370 fp->V[1]=Nv1;
00371 fp->V[2]=lp->extra;
00372 }
00373 lp->extra = -1;
00374 lp->xxtra = -1;
00375 }
00376 }
00377 }
00378 fp++; lp++;
00379 }
00380 }
00381 }
00382 ep++;
00383 }
00384 if(down_to_f < Nface1){
00385 fp=(MainFp+down_to_f); lp=(MainLp+down_to_f);
00386 for(i=down_to_f;i<Nface1;i++){
00387 V0=(MainVp+fp->V[0]);
00388 V1=(MainVp+fp->V[1]);
00389 V2=(MainVp+fp->V[2]);
00390 if(lp->extra >= 0){
00391 if(V0->status == DESELECTED){
00392 if( IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00393 fp->V[0],lp->extra,fp->V[2]))
00394 CreateFace(fp->V[0],lp->extra,fp->V[2]);
00395 else
00396 CreateFace(fp->V[0],fp->V[2],lp->extra);
00397 CopyFaceProp(fp,(MainFp+Nface-1));
00398 CreateEdge(fp->V[0],lp->extra);
00399 fp->V[2] = lp->extra;
00400 }
00401 else if(V1->status == DESELECTED){
00402 if( IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00403 fp->V[1],lp->extra,fp->V[0]))
00404 CreateFace(fp->V[1],lp->extra,fp->V[0]);
00405 else
00406 CreateFace(fp->V[1],fp->V[0],lp->extra);
00407 CopyFaceProp(fp,(MainFp+Nface-1));
00408 CreateEdge(fp->V[1],lp->extra);
00409 fp->V[0] = lp->extra;
00410 }
00411 else if(V2->status == DESELECTED){
00412 if( IsFOSame(fp->V[0],fp->V[1],fp->V[2],
00413 fp->V[2],lp->extra,fp->V[1]))
00414 CreateFace(fp->V[2],lp->extra,fp->V[1]);
00415 else
00416 CreateFace(fp->V[2],fp->V[1],lp->extra);
00417 CopyFaceProp(fp,(MainFp+Nface-1));
00418 CreateEdge(fp->V[2],lp->extra);
00419 fp->V[1] = lp->extra;
00420 }
00421 }
00422 fp++; lp++;
00423 }
00424 }
00425 X__Free(vlist);
00426 if(MainLp != NULL)X__Free(MainLp);
00427 if(MainPp != NULL)X__Free(MainPp);
00428 return OK;
00429 EP1:
00430 if(MainLp != NULL)X__Free(MainLp);
00431 if(MainPp != NULL)X__Free(MainPp);
00432 X__Free(vlist);
00433 return FAIL;
00434 }
00435
00436 static void SetVertexNormalPosition(vertex *Vn, long vc,
00437 VERTEXNORMAL *MainPp, long Pmax){
00438 double l;
00439 vertex *V0;
00440 vector p,dp;
00441 V0=(MainVp+vc);
00442 if(vc >= Pmax || !((MainPp+vc)->set) ){
00443 Vn->xyz[0]=V0->xyz[0];
00444 Vn->xyz[1]=V0->xyz[1];
00445 Vn->xyz[2]=V0->xyz[2];
00446 return;
00447 }
00448 l=(double)TVsizeX/10;
00449 VECCOPY((MainPp+vc)->n,dp)
00450 VECCOPY((double)V0->xyz,p)
00451 Vn->xyz[0]=(long)(p[0]+l*dp[0]);
00452 Vn->xyz[1]=(long)(p[1]+l*dp[1]);
00453 Vn->xyz[2]=(long)(p[2]+l*dp[2]);
00454 return;
00455 }
00456
00457 static int BuildNormals(long down_to_f, long down_to_e){
00458 vector face_normal;
00459 vertex *vp,*V0,*V1,*V2;
00460 face *fp;
00461 long i,Nv1,Nv,Nnormals;
00462 VERTEXNORMAL *MainPp=NULL,*pp;
00463
00464 if(down_to_f < Nface){
00465 Nnormals=Nvert;
00466 if((MainPp=(VERTEXNORMAL *)X__Malloc(Nvert*sizeof(VERTEXNORMAL))) == NULL){
00467 return FAIL;
00468 }
00469 for(i=0,pp=MainPp;i<Nnormals;i++,pp++){
00470 pp->set=FALSE;
00471 pp->n[0] = pp->n[1] = pp->n[2] = 0.0;
00472 }
00473 fp=(MainFp+down_to_f);
00474 for(i=down_to_f;i<Nface;i++){
00475 V0=(MainVp+fp->V[0]); V1=(MainVp+fp->V[1]); V2=(MainVp+fp->V[2]);
00476 if((V0->status == SELECTED && V1->status == SELECTED) ||
00477 (V1->status == SELECTED && V2->status == SELECTED) ||
00478 (V2->status == SELECTED && V0->status == SELECTED)){
00479 if(GetFaceNormal(V0,V1,V2,face_normal)){
00480 VECSUM((MainPp+fp->V[0])->n,face_normal,(MainPp+fp->V[0])->n)
00481 VECSUM((MainPp+fp->V[1])->n,face_normal,(MainPp+fp->V[1])->n)
00482 VECSUM((MainPp+fp->V[2])->n,face_normal,(MainPp+fp->V[2])->n)
00483 (MainPp+fp->V[0])->set=TRUE;
00484 (MainPp+fp->V[1])->set=TRUE;
00485 (MainPp+fp->V[2])->set=TRUE;
00486 }
00487 }
00488 fp++;
00489 }
00490 }
00491 for(i=0,pp=MainPp;i<Nnormals;i++,pp++){
00492 if(pp->set){
00493 if(oNormalize(pp->n) == FAIL)pp->set=FALSE;
00494 }
00495 }
00496 if(!UpdateVertexHeap(Nvert+NvertSelect))goto EP1;
00497 if(!UpdateEdgeHeap(Nedge+NvertSelect))goto EP1;
00498 Nv=Nvert;
00499 for(i=0,vp=MainVp;i<Nv;i++,vp++){
00500 if(vp->status == SELECTED){
00501 CreateVertex(); Nv1=Nvert-1;
00502 SetVertexNormalPosition((MainVp+Nv1),i,MainPp,Nnormals);
00503 CreateEdge(Nv1,i);
00504 }
00505 }
00506 if(MainPp != NULL)X__Free(MainPp);
00507 return OK;
00508 EP1:
00509 if(MainPp != NULL)X__Free(MainPp);
00510 return FAIL;
00511 }