bool ON_Mesh::CollapseEdge( int topei ) { ON_Mesh& mesh = *this; ON__MESHEDGE me; memset(&me,0,sizeof(me)); const ON_MeshTopology& top = mesh.Topology(); const int F_count = mesh.m_F.Count(); const int V_count = mesh.m_V.Count(); const int topv_count = top.m_topv.Count(); //const int tope_count = top.m_tope.Count(); if ( topei < 0 || topei >= top.m_tope.Count() ) { return false; } const ON_MeshTopologyEdge& tope = top.m_tope[topei]; if ( tope.m_topf_count < 1 || tope.m_topvi[0] == tope.m_topvi[1] || tope.m_topvi[0] < 0 || tope.m_topvi[1] < 0 || tope.m_topvi[0] >= topv_count || tope.m_topvi[1] >= topv_count ) { return false; } const ON_MeshTopologyVertex& topv0 = top.m_topv[tope.m_topvi[0]]; const ON_MeshTopologyVertex& topv1 = top.m_topv[tope.m_topvi[1]]; if ( topv0.m_v_count < 1 || topv1.m_v_count < 1 ) { return false; } if ( topv0.m_vi[0] < 0 || topv0.m_vi[0] >= V_count ) { return false; } if ( topv1.m_vi[0] < 0 || topv1.m_vi[0] >= V_count ) { return false; } // create a ON__MESHEDGE for each face (usually one or two) that uses the edge ON__MESHEDGE* me_list = (ON__MESHEDGE*)alloca(tope.m_topf_count*sizeof(me_list[0])); int me_list_count = 0; int efi; for ( efi = 0; efi < tope.m_topf_count; efi++ ) { int fi = tope.m_topfi[efi]; if ( fi < 0 || fi >= F_count ) continue; const ON_MeshFace& f = mesh.m_F[fi]; if ( !f.IsValid(V_count) ) continue; me.vi1 = f.vi[3]; me.topvi1 = top.m_topv_map[me.vi1]; int fvi; for ( fvi = 0; fvi < 4; fvi++ ) { me.vi0 = me.vi1; me.topvi0 = me.topvi1; me.vi1 = f.vi[fvi]; me.topvi1 = top.m_topv_map[me.vi1]; if ( me.vi0 != me.vi1 ) { if ( (me.topvi0 == tope.m_topvi[0] && me.topvi1 == tope.m_topvi[1]) || (me.topvi0 == tope.m_topvi[1] && me.topvi1 == tope.m_topvi[0]) ) { if ( me.vi0 > me.vi1 ) { int i = me.vi0; me.vi0 = me.vi1; me.vi1 = i; i = me.topvi0; me.topvi0 = me.topvi1; me.topvi1 = i; } me_list[me_list_count++] = me; break; } } } } if (me_list_count<1) { return false; } // Sort me_list[] so edges using same vertices are adjacent // to each other in the list. This is needed so that non-manifold // crease edges will be properly collapsed. ON_qsort(me_list,me_list_count,sizeof(me_list[0]),(QSORTCMPFUNC)CompareMESHEDGE); // create new vertex or vertices that edge will be // collapsed to. mesh.m_C.Destroy(); mesh.m_K.Destroy(); int mei; bool bHasVertexNormals = mesh.HasVertexNormals(); bool bHasTextureCoordinates = mesh.HasTextureCoordinates(); bool bHasFaceNormals = mesh.HasFaceNormals(); if ( topv0.m_v_count == 1 || topv1.m_v_count == 1 ) { // a single new vertex ON_Line Vline(ON_origin,ON_origin); ON_Line Tline(ON_origin,ON_origin); ON_3dVector N0(0,0,0); ON_3dVector N1(0,0,0); ON_3dPoint P; int vi, tvi, cnt; int newvi = topv0.m_vi[0]; cnt = 0; for ( tvi = 0; tvi < topv0.m_v_count; tvi++ ) { vi = topv0.m_vi[tvi]; if ( vi < 0 || vi > V_count ) continue; if ( vi < newvi ) newvi = vi; cnt++; P = mesh.m_V[vi]; Vline.from += P; if ( bHasVertexNormals ) { N0 += ON_3dVector(mesh.m_N[vi]); } if ( bHasTextureCoordinates ) { P = mesh.m_T[vi]; Tline.from += P; } } if (cnt > 1) { double s = 1.0/((double)cnt); Vline.from.x *= s; Vline.from.y *= s; Vline.from.z *= s; Tline.from.x *= s; Tline.from.y *= s; Tline.from.z *= s; N0 = s*N0; } cnt = 0; for ( tvi = 0; tvi < topv1.m_v_count; tvi++ ) { vi = topv1.m_vi[tvi]; if ( vi < 0 || vi > V_count ) continue; if ( vi < newvi ) newvi = vi; cnt++; P = mesh.m_V[vi]; Vline.to += P; if ( bHasVertexNormals ) { N1 += ON_3dVector(mesh.m_N[vi]); } if ( bHasTextureCoordinates ) { P = mesh.m_T[vi]; Tline.to += P; } } if (cnt > 1) { double s = 1.0/((double)cnt); Vline.to.x *= s; Vline.to.y *= s; Vline.to.z *= s; Tline.to.x *= s; Tline.to.y *= s; Tline.to.z *= s; N1 = s*N1; } ON_3fPoint newV(Vline.PointAt(0.5)); ON_3fVector newN; ON_2fPoint newT; if ( bHasVertexNormals ) { N0.Unitize(); N1.Unitize(); ON_3dVector N = N0+N1; if ( !N.Unitize() ) { N = (topv0.m_v_count == 1) ? mesh.m_N[topv0.m_vi[0]] :mesh.m_N[topv1.m_vi[0]]; } newN = N; } if ( bHasTextureCoordinates ) { newT = Tline.PointAt(0.5); } for ( mei = 0; mei < me_list_count; mei++ ) { me_list[mei].newvi = newvi; me_list[mei].newV = newV; me_list[mei].newN = newN; me_list[mei].newT = newT; } } else { // collapsing a "crease" edge - attempt to preserve // the crease. memset(&me,0,sizeof(me)); me.vi0 = -1; me.vi1 = -1; for ( mei = 0; mei < me_list_count; mei++ ) { if ( 0 == mei && CompareMESHEDGE(&me,me_list+mei) ) { // cook up new vertex me_list[mei].newvi = mesh.m_V.Count(); me = me_list[mei]; ON_Line line; line.from = mesh.m_V[me.vi0]; line.to = mesh.m_V[me.vi1]; me.newV = line.PointAt(0.5); if ( bHasVertexNormals ) { ON_3dVector N0(mesh.m_N[me.vi0]); ON_3dVector N1(mesh.m_N[me.vi1]); ON_3dVector N = N0 + N1; if ( !N.Unitize() ) N = N0; me.newN = N; } if ( bHasTextureCoordinates ) { line.from = mesh.m_T[me.vi0]; line.to = mesh.m_T[me.vi1]; me.newT = line.PointAt(0.5); } me.newvi = (me.vi0 < me.vi1) ? me.vi0 : me.vi1; } else { me_list[mei].newvi = me.newvi; me_list[mei].newV = me.newV; me_list[mei].newN = me.newN; me_list[mei].newT = me.newT; } } } // We are done averaging old mesh values. // Change values in mesh m_V[], m_N[] and m_T[] arrays. for ( mei = 0; mei < me_list_count; mei++ ) { mesh.m_V[me_list[mei].vi0] = me_list[mei].newV; mesh.m_V[me_list[mei].vi1] = me_list[mei].newV; if ( bHasVertexNormals ) { mesh.m_N[me_list[mei].vi0] = me_list[mei].newN; mesh.m_N[me_list[mei].vi1] = me_list[mei].newN; } if ( bHasTextureCoordinates ) { mesh.m_T[me_list[mei].vi0] = me_list[mei].newT; mesh.m_T[me_list[mei].vi1] = me_list[mei].newT; } } // make a map of old to new int old2new_map_count = 0; ON__NEWVI* old2new_map = (ON__NEWVI*)alloca(2*me_list_count*sizeof(old2new_map[0])); for ( mei = 0; mei < me_list_count; mei++ ) { old2new_map[old2new_map_count].oldvi = me_list[mei].vi0; old2new_map[old2new_map_count].newvi = me_list[mei].newvi; old2new_map_count++; old2new_map[old2new_map_count].oldvi = me_list[mei].vi1; old2new_map[old2new_map_count].newvi = me_list[mei].newvi; old2new_map_count++; } // sort old2new_map[] so we can use a fast bsearch() call // to update faces. ON_qsort(old2new_map,old2new_map_count,sizeof(old2new_map[0]),(QSORTCMPFUNC)CompareNEWVI); // count faces that use the vertices that are being changed int bad_fi_count = 0; int topv_end, vei, fi, fvi23, fvi; ON__NEWVI nvi; for ( topv_end = 0; topv_end < 2; topv_end++ ) { const ON_MeshTopologyVertex& topv = (topv_end) ? topv1 : topv0; for ( vei = 0; vei < topv.m_tope_count; vei++ ) { topei = topv.m_topei[vei]; if ( topei < 0 && topei >= top.m_tope.Count() ) continue; bad_fi_count += top.m_tope[topei].m_topf_count; } } int* bad_fi = (int*)alloca(bad_fi_count*sizeof(*bad_fi)); bad_fi_count = 0; // Go through all the faces that use the vertices at the // ends of the edge and update the vi[] values to use the // new vertices. for ( topv_end = 0; topv_end < 2; topv_end++ ) { const ON_MeshTopologyVertex& topv = (topv_end) ? topv1 : topv0; for ( vei = 0; vei < topv.m_tope_count; vei++ ) { topei = topv.m_topei[vei]; if ( topei < 0 && topei >= top.m_tope.Count() ) continue; const ON_MeshTopologyEdge& e = top.m_tope[topei]; for ( efi = 0; efi < e.m_topf_count; efi++ ) { fi = e.m_topfi[efi]; if ( fi < 0 || fi >= F_count ) continue; bool bChangedFace = false; ON_MeshFace& f = mesh.m_F[fi]; for ( fvi = 0; fvi < 4; fvi++ ) { nvi.oldvi = f.vi[fvi]; ON__NEWVI* p = (ON__NEWVI*)bsearch(&nvi,old2new_map,old2new_map_count,sizeof(old2new_map[0]),(QSORTCMPFUNC)CompareNEWVI); if ( 0 != p && p->oldvi != p->newvi) { f.vi[fvi] = p->newvi; bChangedFace = true; } } if ( bChangedFace ) { if ( !f.IsValid(V_count) ) { if ( f.vi[3] == f.vi[0] ) { f.vi[0] = f.vi[1]; f.vi[1] = f.vi[2]; f.vi[2] = f.vi[3]; } else if ( f.vi[0] == f.vi[1] ) { fvi23 = f.vi[0]; f.vi[0] = f.vi[2]; f.vi[1] = f.vi[3]; f.vi[2] = fvi23; f.vi[3] = fvi23; } else if ( f.vi[1] == f.vi[2] ) { fvi23 = f.vi[1]; f.vi[1] = f.vi[0]; f.vi[0] = f.vi[3]; f.vi[2] = fvi23; f.vi[3] = fvi23; } if ( f.vi[0] == f.vi[1] || f.vi[1] == f.vi[2] || f.vi[2] == f.vi[0] || f.vi[2] != f.vi[3] ) { bad_fi[bad_fi_count++] = fi; } } if ( bHasFaceNormals ) { // invalid faces are removed below ON_3fVector a, b, n; a = mesh.m_V[f.vi[2]] - mesh.m_V[f.vi[0]]; b = mesh.m_V[f.vi[3]] - mesh.m_V[f.vi[1]]; n = ON_CrossProduct( a, b ); n.Unitize(); mesh.m_FN[fi] = n; } } } } } if ( bad_fi_count > 0 ) { // remove collapsed faces ON_qsort(bad_fi,bad_fi_count,sizeof(bad_fi[0]),CompareInt); int bfi = 1; int dest_fi = bad_fi[0]; for ( fi = dest_fi+1; fi < F_count && bfi < bad_fi_count; fi++ ) { if ( fi == bad_fi[bfi] ) { bfi++; } else { mesh.m_F[dest_fi++] = mesh.m_F[fi]; } } while (fi<F_count) { mesh.m_F[dest_fi++] = mesh.m_F[fi++]; } mesh.m_F.SetCount(dest_fi); if ( bHasFaceNormals ) { bfi = 1; dest_fi = bad_fi[0]; for ( fi = dest_fi+1; fi < F_count && bfi < bad_fi_count; fi++ ) { if ( fi == bad_fi[bfi] ) { bfi++; } else { mesh.m_FN[dest_fi++] = mesh.m_FN[fi]; } } while (fi<F_count) { mesh.m_FN[dest_fi++] = mesh.m_FN[fi++]; } mesh.m_FN.SetCount(dest_fi); } } mesh.Compact(); mesh.DestroyTopology(); mesh.DestroyPartition(); return true; }
// ----------------------------------------------- // ProgressBar // ----------------------------------------------- void * ehzProgressBar(struct OBJ *objCalled,EN_MESSAGE cmd,LONG info,void *ptr) { EH_DISPEXT *DExt=ptr; // SINT *lpi; SINT iLx,iLy; SINT iRiemp; SINT iPos; SINT iBar; SINT iDiv; SINT a; SINT ThePoint; SINT iMyShadow; SINT iEnd; EH_PROGRESS_BAR * psBar; //lpi=(SINT *) objCalled->text; psBar=(EH_PROGRESS_BAR *) objCalled->pOther; switch(cmd) { case WS_INF: return NULL; case WS_CREATE: psBar=objCalled->pOther=ehAllocZero(sizeof(EH_PROGRESS_BAR)); psBar->iMax=100; psBar->cBar=sys.Color3DHighLight; if (!strcmp(objCalled->text,"WIN")) { objCalled->hWnd=CreateWindowEx(0, PROGRESS_CLASS, NULL, WS_CHILD|WS_VISIBLE, 0,0, 10,10,//-(MENU_HEIGHT), WindowNow(),//sGMSetup.hwAnagTB,//sGMSetup.hwAnag, (HMENU) NULL, sys.EhWinInstance, NULL); SendMessage(objCalled->hWnd, PBM_SETRANGE,0,MAKELPARAM(0,100)); SendMessage(objCalled->hWnd, PBM_SETSTEP, MAKEWPARAM(1, 0), 0); } else objCalled->hWnd=NULL; break; case WS_DESTROY: ehFreePtr(&objCalled->pOther); if (objCalled->hWnd) DestroyWindow(objCalled->hWnd); break; case WS_DO: // Spostamento / Ridimensionamento MoveWindow(objCalled->hWnd,DExt->px,DExt->py,DExt->lx,DExt->ly,TRUE); break; case WS_SETFLAG: if (!strcmp(ptr,"MAX")) // Setta lo stile della finestra { if (info<1) info=1; //*psBar->iMax=info; psBar->iMax=info; } if (!strcmp(ptr,"COL")) // Setta lo stile della finestra { // *(lpi+3)=info; psBar->cBar=info; obj_vedisolo(objCalled->nome); } if (!strcmp(ptr,"CNT")) // Setta lo stile della finestra { //*lpi=info; psBar->iCount=info; // Calcolo percentuale iRiemp=psBar->iCount; if (iRiemp>(psBar->iMax)) iRiemp=psBar->iMax; iPos=0; if (psBar->iMax) iPos=100*iRiemp/psBar->iMax;// calcolo percntuale di riempimento // Se la percentuale è cambiata ristampo il tutto if (psBar->iPerc!=iPos) { psBar->iPerc=iPos; if (objCalled->hWnd) SendMessage(objCalled->hWnd, PBM_SETPOS, psBar->iPerc, 0); else obj_vedisolo(objCalled->nome); } //if (*lpi!=info) {*lpi=info; obj_vedisolo(objCalled->nome);} } break; case WS_DISPLAY: if (objCalled->hWnd) {InvalidateRect(objCalled->hWnd,NULL,TRUE); break;} iLx=DExt->px+DExt->lx-1; iLy=DExt->py+DExt->ly-1; iRiemp=psBar->iCount; if (iRiemp>(psBar->iMax)) iRiemp=psBar->iMax; iPos=100*iRiemp/psBar->iMax;// calcolo percentuale di riempimento iBar=(DExt->lx-3)*iRiemp/psBar->iMax;// Calcolo dimensione barra pieno iDiv=(DExt->px+iBar); //Tbox(DExt->px,DExt->py,iLx,iLy,0,SET); box3d(DExt->px,DExt->py,iLx,iLy,1); // dispf(iText,DExt->py,15,-1,ON,"SMALL F",3,szServ); ThePoint=(DExt->ly/3); iMyShadow=ColorLum(sys.Color3DShadow,-30); if (iBar>0) { Tline(DExt->px+1,DExt->py+1,iDiv,DExt->py+1,iMyShadow,SET); for (a=2;a<DExt->ly-2;a++) { LONG Col; if (a<ThePoint) Col=ColorFusion(sys.Color3DShadow,psBar->cBar,(100/ThePoint*a)); else Col=ColorFusion(sys.Color3DShadow,psBar->cBar,(100/(DExt->ly-ThePoint)*(DExt->ly-a))); // iEnd=iDiv+a-2; if (iEnd>iLx-1) iEnd=iLx-1; iEnd=iDiv-2; if (iEnd>iLx-1) iEnd=iLx-1; Tline(DExt->px+2,DExt->py+a,iEnd,DExt->py+a,Col,SET); } Tline(DExt->px+1,iLy-1,iEnd,iLy-1,ColorLum(sys.Color3DShadow,-40),SET); } ThePoint=DExt->ly-ThePoint; if (iBar<(DExt->lx-2)) {//Tboxp(iDiv+1,DExt->py+2,iDiv+1,iLy-2,0,SET); //Tboxp(iDiv+2,DExt->py+1,iLx-1,iLy-1,ColorLum(sys.Color3DShadow,-10),SET); for (a=1;a<DExt->ly-1;a++) { LONG Col; if (a<ThePoint) Col=ColorFusion(iMyShadow,sys.Color3DLight,(100/ThePoint*a)); else Col=ColorFusion(iMyShadow,sys.Color3DLight,(100/(DExt->ly-ThePoint)*(DExt->ly-a))); // if (iBar>0) {iEnd=iDiv+a; if (iEnd>iLx-1) iEnd=iLx-1;} else iEnd=iDiv+1; if (iBar>0) {iEnd=iDiv-1; if (iEnd>iLx-1) iEnd=iLx-1;} else iEnd=iDiv+1; Tline(iEnd,DExt->py+a,iLx-1,DExt->py+a,Col,SET); } } //sys.fFontBold=FALSE; break; } return NULL; }