/** @brief 三角Contour(Face)用ライブラリ @file TriBrep.cpp @author Fumi.Iseki (C) @attention このファイルの関数は Contour(=Face)が三角形であることを前提とする. */ #include "TriBrep.h" using namespace jbxl; /** DllExport void CreateContoursRing(SOLID* solid) 削除マークの付いたContour(Face)を削除し,全Contour(Face)の Ringを作る.@n ただし,読み込み(初期)データは削除しない. */ DllExport void CreateContoursRing(SOLID* solid) { solid->contours.clear(); BREP_SHELL_RING shells = solid->shells; BREP_SHELL_RING::iterator ishell; for (ishell=shells.begin(); ishell!=shells.end(); ishell++){ BREP_FACE* pbfc; BREP_FACE_RING::iterator iface; for (iface =(*ishell)->faces.begin(); iface!=(*ishell)->faces.end(); iface++){ if (((FACE*)(*iface))->deletable && !(((FACE*)(*iface))->initdata)) { pbfc = *iface; iface = (*ishell)->faces.erase(iface); iface--; pbfc->shell = NULL; delete(pbfc); } else { BREP_CONTOUR_RING::iterator icon; for (icon=(*iface)->outer_contours.begin(); icon!=(*iface)->outer_contours.end(); icon++) { ((FACE*)(*iface))->deletable = false; solid->contours.push_back(*icon); } } } } solid->facetno = (int)solid->contours.size(); } /** DllExport void CreateWingsRing(SOLID* solid) 全 Wingの Ringを作る.(Contourに結び付けられていないものも含む) @n CreateContoursRing()に依存する. */ DllExport void CreateWingsRing(SOLID* solid) { solid->wings.clear(); BREP_CONTOUR_RING::iterator icon; for (icon=solid->contours.begin(); icon!=solid->contours.end(); icon++) { BREP_WING* first = (*icon)->wing; if (first!=NULL) { BREP_WING* next = first; do { BREP_WING* wing = next; next = wing->next; solid->wings.push_back(wing); if (!wing->edge->complete) solid->wings.push_back(BrepEdgeOtherWing(wing)); } while(next!=first); } } } /** DllExport void CreateSurplusContoursRing(SOLID* solid) 多重Edgeを持つ Contourの Ringを作る.@n CreateContoursRing()に依存する. */ DllExport void CreateSurplusContoursRing(SOLID* solid) { // DEBUG_MODE print_messageln("Start CreateSurplusContoursRing"); solid->surplus_contours.clear(); BREP_CONTOUR_RING::iterator icon; for (icon=solid->contours.begin(); icon!=solid->contours.end(); icon++){ if (DupEdgeNumber((CONTOUR*)(*icon))>0) { solid->surplus_contours.push_back(*icon); } } // DEBUG_MODE print_messageln("END CreateSurplusContoursRing"); } /** DllExport void CreateShortageWingsRing(SOLID* solid) 不完全な Wingの Ringを作る.WingsRingを利用する.@n CreateContoursRing(), CreateWingsRing()に依存する. */ DllExport void CreateShortageWingsRing(SOLID* solid) { solid->shortage_wings.clear(); BREP_WING_RING::iterator iwing; for (iwing=solid->wings.begin(); iwing!=solid->wings.end(); iwing++){ if ((*iwing)->contour==NULL) solid->shortage_wings.push_back(*iwing); } } //--------------------------------------------------------------------------------------------------------- /** DllExport void DeleteSurplusContours(SOLID* solid) 多重Edgeを持つ Contour(Face)の削除 @n Contours Ring と Wings Ringの内容は保障される. @par 要求データ - 全てのContour(Face)の Ring (Contours Ring). - 外側の関数で行う.CreateContoursRing()を使用しても良い. - 多重エッジの数が1以上のContour(Face)が格納された作業Ring(SurplusContours Ring). - 外側の関数で行う.CreateSuplusContoursRing()を使用しても良い @par アルゴリズム -# 作業Ringの中にある3辺が多重EdgeのFaceに削除マークをつける(高速化のため) - 該当Face(Contour)を削除し,そのFace(Contour)を裏返して登録する (ReverseContours) - 多重Edgeが一つでもある場合は登録を中止 -# 2辺が多重Edgeの Faceに削除マークをつける.1と同様の処理を行う. -# 1辺が多重Edgeの Faceに削除マークをつける.1と同様の処理を行う. -# この段階で,作業Ringの中には Faceは存在しないはず.まだ存在する場合はエラー. */ DllExport void DeleteSurplusContours(SOLID* solid) { if (solid->surplus_contours.empty()) return; // DEBUG_MODE print_messageln("Start DeleteSurplusContours"); CVCounter* counter = NULL; if (solid->counter!=NULL) counter = solid->counter->GetUsableCounter(); if (counter!=NULL) counter->SetMax((int)solid->surplus_contours.size()*3); BREP_CONTOUR_RING::iterator icon; // 3つの多重Edgeを持つ Faceの処理 for (icon=solid->surplus_contours.begin(); icon!=solid->surplus_contours.end(); icon++){ if ((*icon)->dup_edge==3) ((FACE*)((*icon)->face))->deletable = true; if (counter!=NULL) counter->StepIt(); } ReverseContours(solid); // 3辺が多重Edgeの Faceを裏返す CreateShortageWingsRing(solid); JoinShortageWings(solid); // 一つにまとまるEdgeは一つにまとめる. CreateSurplusContoursRing(solid); if (solid->surplus_contours.empty()) { // DEBUG_MODE print_messageln("End DeleteSurplusContours"); return; } // 2つの多重Edgeを持つ Faceの処理 for (icon=solid->surplus_contours.begin(); icon!=solid->surplus_contours.end(); icon++){ if ((*icon)->dup_edge==2) ((FACE*)((*icon)->face))->deletable = true; if (counter!=NULL) counter->StepIt(); } ReverseContours(solid); // 2辺が多重Edgeの Faceを裏返す CreateShortageWingsRing(solid); JoinShortageWings(solid); CreateSurplusContoursRing(solid); if (solid->surplus_contours.empty()) { // DEBUG_MODE print_messageln("End DeleteSurplusContours"); return; } // 1つの多重Edgeを持つ Faceの処理 for (icon=solid->surplus_contours.begin(); icon!=solid->surplus_contours.end(); icon++){ if ((*icon)->dup_edge==1) ((FACE*)((*icon)->face))->deletable = true; if (counter!=NULL) counter->StepIt(); } ReverseContours(solid); // 1辺が多重Edgeの Faceを裏返す CreateShortageWingsRing(solid); JoinShortageWings(solid); CreateSurplusContoursRing(solid); if (!solid->surplus_contours.empty()) { // DEBUG_MODE print_messageln("EraseSurplusContour: 多重Edgeを持つ Faceデータが残っている?"); } // DEBUG_MODE print_messageln("End DeleteSurplusContours"); return; } /** DllExport void DeleteStraightEdges(SOLID* solid) 複数のVertexが直線に並んだ場合,両端のVertex間に作られた Edge(Wing)に関連する Contour(Face)を削除.@n Contours Ring と Wings Ringの内容は保障される. @par 要求データ - 全てのWingの Ring(Wings Ring). - 外側の関数で行う.CreateWingsRing()を使用しても良い. - Contourに関連付けられていない(使用されていない)Wingが格納された作業Ring(ShortageWings Ring). - 外側の関数で行う.CreateShortageWingsRing() を使用しても良い. */ DllExport void DeleteStraightEdges(SOLID* solid) { if (solid->shortage_wings.empty()) return; // DEBUG_MODE print_messageln("Start DeleteStraightEdges"); CVCounter* counter = NULL; if (solid->counter!=NULL) counter = solid->counter->GetUsableCounter(); if (counter!=NULL) counter->SetMax((int)solid->shortage_wings.size()); BREP_WING_RING::iterator wing1; for (wing1=solid->shortage_wings.begin(); wing1!=solid->shortage_wings.end(); wing1++){ VERTEX* vert[3]; vert[0] = (VERTEX*)((*wing1)->vertex); BREP_WING_RING::iterator wing2; for (wing2=solid->shortage_wings.begin(); wing2!=solid->shortage_wings.end(); wing2++){ if (IsConnectEdges(*wing1, *wing2)) { vert[1] = (VERTEX*)((*wing2)->vertex); vert[2] = (VERTEX*)(BrepEdgeOtherWing(*wing2)->vertex); IsForbiddenEdge(vert); // 直線に並んだ Vertexを禁止する. } } if (counter!=NULL) counter->StepIt(); } CreateContoursRing(solid); // 該当Contour(Face)を削除し,全てのContour(Face)の Ringを作り直す. CreateWingsRing(solid); // WingsRingを作り直す. // DEBUG_MODE print_messageln("End DeleteStraightEdges"); return; } /** DllExport void DeleteShortageWings(SOLID* solid) 不完全 Wing(Edge)を持つFace(Contour)を削除 @n Contours Ring と Wings Ringの内容は保障される. @par 要求データ - ShortageWings Ring.CreateShortageWingsRing()で作成しても良い */ DllExport void DeleteShortageWings(SOLID* solid) { if (solid->shortage_wings.empty()) return; // DEBUG_MODE print_messageln("Start DeleteShortageWings"); CVCounter* counter = NULL; if (solid->counter!=NULL) counter = solid->counter->GetUsableCounter(); if (counter!=NULL) counter->SetMax((int)solid->shortage_wings.size()); BREP_WING_RING::iterator iwing; for (iwing=solid->shortage_wings.begin(); iwing!=solid->shortage_wings.end(); iwing++){ if ((*iwing)->contour!=NULL) ((FACE*)((*iwing)->contour->face))->deletable = true; BREP_WING* othwing = BrepEdgeOtherWing(*iwing); if (othwing->contour!=NULL) ((FACE*) (othwing->contour->face))->deletable = true; if (counter!=NULL) counter->StepIt(); } CreateContoursRing(solid); CreateWingsRing(solid); // DEBUG_MODE print_messageln("End DeleteShortageWings"); return; } #define MAX_LOOP_CNT 20 /** DllExport void FillShortageWings(SOLID* solid, int method, bool mode) 足りないContourを補充する(全ての不足Contourが無くなるか,補充不可能になるまで).@n Contours Ring, Wings Ring, SohrtageWins Ringの内容は保障される. @par 要求データ - ShortageWings Ring.CreateShortageWingsRing()で作成しても良い @param solid ソリッドデータへのポインタ @param method @b 1: 三番目のVertexを探すアルゴリズムは Next. @param method @b 2: 三番目のVertexを探すアルゴリズムは Near. @param mode @b true : 多重Edgeを認める. @param mode @b false: 多重Edgeを認めない. */ DllExport void FillShortageWings(SOLID* solid, int method, bool mode) { if (solid->shortage_wings.empty()) return; // DEBUG_MODE print_messageln("Start FillShortageWings"); int wmax = (int)solid->shortage_wings.size(); CVCounter* counter = NULL; if (solid->counter!=NULL) counter = solid->counter->GetUsableCounter(); if (counter!=NULL) counter->SetMax(wmax); int lpc = 0; int pno = 1; while (solid->shortage_wings.size()>1 && pno!=0 && lpcshortage_wings.size(), wmax, pno); lpc++; } // DEBUG_MODE print_messageln("End FillShortageWings"); return; } /** DllExport int FillShortageWings_Next(SOLID* solid, bool mode) 足りないContourを補充する(一周期のみ).Nextアルゴリズム Edgeに繋がっているEdgeを探してそのVertexから三角形(Contour)を作る.@n Contours Ring と Wings Ringの内容は保障される. @par 要求データ - ShortageWings Ring.CreateShortageWingsRing()で作成しても良い @param solid ソリッドデータへのポインタ @param mode @b true : 多重Edgeを認める. @param mode @b false: 多重Edgeを認めない. */ DllExport int FillShortageWings_Next(SOLID* solid, bool mode) { int patchno = 0; BREP_WING_RING::iterator wing1; for (wing1=solid->shortage_wings.begin(); wing1!=solid->shortage_wings.end(); wing1++){ //if ((*wing1)->contour==NULL) { if (!IsIncludeCompleteEdge(*wing1)) { VERTEX* vert[3]; vert[0] = (VERTEX*)((*wing1)->vertex); BREP_WING_RING::iterator wing2; for (wing2=solid->shortage_wings.begin(); wing2!=solid->shortage_wings.end(); wing2++){ //if ((*wing2)->contour==NULL && IsConnectEdges(*wing1, *wing2)) { if (!IsIncludeCompleteEdge(*wing2) && IsConnectEdges(*wing1, *wing2)) { vert[1] = (VERTEX*)((*wing2)->vertex); vert[2] = (VERTEX*)(BrepEdgeOtherWing(*wing2)->vertex); // vert[]: Contourを貼る頂点 SHELL* shell = (SHELL*)(BrepEdgeOtherWing(*wing1)->contour->face->shell); if (PatchupContour(shell, vert, mode)) patchno++; } } } // if (patchno>5) break; } CreateContoursRing(solid); CreateWingsRing(solid); return patchno; } #define MAX_QUEUE_SIZE 1 /** DllExport int FillShortageWings_Near(SOLID* solid, bool mode) 足りないContourを補充する(一周期のみ).Nearアルゴリズム Edgeの中心から近いVertexを探して三角形(Contour)を作る.@n Contours Ring と Wings Ringの内容は保障される. @par 要求データ - ShortageWings Ring.CreateShortageWingsRing()で作成しても良い @param solid ソリッドデータへのポインタ @param mode @b true : 多重Edgeを認める. @param mode @b false: 多重Edgeを認めない. */ DllExport int FillShortageWings_Near(SOLID* solid, bool mode) { int patchno = 0; BREP_VERTEX_RING vertex_ring; BREP_WING_RING::iterator wing1; for (wing1=solid->shortage_wings.begin(); wing1!=solid->shortage_wings.end(); wing1++){ //if ((*wing1)->contour==NULL) { if (!IsIncludeCompleteEdge(*wing1)) { // double min = HUGE_VAL; VERTEX* vert[3]; vert[0] = (VERTEX*)((*wing1)->vertex); vert[1] = (VERTEX*)(BrepEdgeOtherWing(*wing1)->vertex); vert[2] = NULL; vertex_ring.clear(); BREP_WING_RING::iterator wing2; for (wing2=solid->shortage_wings.begin(); wing2!=solid->shortage_wings.end(); wing2++){ if (wing1!=wing2) { VERTEX* vrtx = (VERTEX*)((*wing2)->vertex); if (vrtx!=vert[0] && vrtx!=vert[1]) { /* int cnt = 0; VERTEX* v = vert[1]; do { v = FindConnectEdgeVertex(v); cnt++; } while (v!=vert[0] && v!=vert[1] && v!=vrtx && v!=NULL && cnt<100); */ // if (v!=vrtx) { VECTOR vect = (*wing1)->edge->center - vrtx->point; vrtx->distance2 = vect.norm2(); SetMinVertex(&vertex_ring, vrtx); // } } } } int cnt=0; SHELL* shell = (SHELL*)(BrepEdgeOtherWing(*wing1)->contour->face->shell); BREP_VERTEX_RING::iterator ivert; for (ivert=vertex_ring.begin(); ivert!=vertex_ring.end(); ivert++){ vert[2] = (VERTEX*)(*ivert); if (PatchupContour(shell, vert, mode)) { patchno++; break; } cnt++; if (cnt>=MAX_QUEUE_SIZE) break; } } // if (patchno>6) break; } CreateContoursRing(solid); CreateWingsRing(solid); return patchno; } /** DllExport void SetMinVertex(BREP_VERTEX_RING* ring, VERTEX* vrtx) FillShortageWings_Near()用 */ DllExport void SetMinVertex(BREP_VERTEX_RING* ring, VERTEX* vrtx) { BREP_VERTEX_RING::iterator ivert; for (ivert=ring->begin(); ivert!=ring->end(); ivert++){ if (vrtx==(*ivert)) return; // 既に登録済み if (vrtx->distance2 < ((VERTEX*)(*ivert))->distance2) { ring->insert(ivert, vrtx); return; } } if (ivert==ring->end()) ring->push_back(vrtx); return; } /** DllExport VERTEX* FindConnectEdgeVertex(VERTEX* vert) vertexと Edgeで繋がった vertexの内,最初に見つけたものを返す. */ DllExport VERTEX* FindConnectEdgeVertex(VERTEX* vert) { BREP_WING_RING::iterator iwing; for (iwing=vert->wing_ring.begin(); iwing!=vert->wing_ring.end(); iwing++){ if ((*iwing)->contour==NULL) { return (VERTEX*)(BrepEdgeOtherWing(*iwing)->vertex); } } return NULL; } /** DllExport bool PatchupContour(SHELL* shell, VERTEX** vert, bool mode) Shellに対して,vert[0]〜vert[2]の三角形Contourを補充する. @param shell シェルデータへのポインタ @param[in,out] vert 頂点情報.補填された三角形の頂点情報が追加される. @param mode @b true: 多重Edgeを認める. @param mode @b false: 多重Edgeを認めない. */ DllExport bool PatchupContour(SHELL* shell, VERTEX** vert, bool mode) { if (vert[0]->forbidden_ring!=NULL) { BREP_VERTEX_RING::iterator vertex; vertex = std::find(vert[0]->forbidden_ring->begin(), vert[0]->forbidden_ring->end(), vert[2]); if (vertex!=vert[0]->forbidden_ring->end()) return false; // 禁止Ringの中に見つけた. } SOLID* solid = (SOLID*)(shell->solid); CVCounter* counter = NULL; if (solid->counter!=NULL) counter = solid->counter->GetUsableCounter(); FACE* face = new FACE(shell); CONTOUR* contour = CreateContourByVertex(face, vert, false); if (contour!=NULL) { if (DupEdgeNumber(contour)==0 || mode) { CONTOUR* collision; face->DataCloseCallback(); if (!IsCollisionContours(solid, contour, &collision)) { solid->contours.push_back(contour); // PrintFacetAsciiSTL(contour); if (counter!=NULL) counter->StepIt(); return true; } else FastDeleteFace(face); } else FastDeleteFace(face); } else FastDeleteFace(face); return false; } /** DllExport void ReverseContours(SOLID* solid) 削除マークの付いたFace(Contour)を削除し,同じ頂点を持つContourを裏返して登録する. もし,登録した Contourに多重 Edgeがある場合は登録を中止する.@n ただし,読み込み(初期)データは削除しない. Contours Ring と Wings Ringの内容は保障される. */ DllExport void ReverseContours(SOLID* solid) { // 全ての Faceに対して BREP_SHELL_RING shells = solid->shells; BREP_SHELL_RING::iterator ishell; for (ishell=shells.begin(); ishell!=shells.end(); ishell++){ BREP_FACE_RING::iterator iface; for (iface =(*ishell)->faces.begin(); iface!=(*ishell)->faces.end(); iface++){ // 削除マークが付いているなら if (((FACE*)(*iface))->deletable && !((FACE*)(*iface))->initdata) { // 逆周りで頂点を VECTOR vに格納 VERTEX* v[3]; FACE* pbfc; CONTOUR* pbcn; BREP_CONTOUR_RING::iterator icon; for (icon=(*iface)->outer_contours.begin(); icon!=(*iface)->outer_contours.end(); icon++) { BREP_WING* wing = (*icon)->wing; for (int i=0; i<3; i++) { v[i] = (VERTEX*)(wing->vertex); wing = wing->prev; } } // 削除マークが付いている Faceを削除 pbfc = (FACE*)*iface; iface = (*ishell)->faces.erase(iface); iface--; pbfc->shell = NULL; delete(pbfc); // 裏返しの Contourを登録 pbfc = new FACE((SHELL*)*ishell); pbcn = CreateContourByVertex(pbfc, v, false); if (pbcn!=NULL) { if (DupEdgeNumber(pbcn)==0) { pbfc->DataCloseCallback(); } else { FastDeleteFace(pbfc); } } else { FastDeleteFace(pbfc); } } } } CreateContoursRing(solid); CreateWingsRing(solid); } /** DllExport void JoinShortageWings(SOLID* solid) 不完全かつ多重Edgeになっているが,実は一つのEdgeにまとめることができるものを一つにまとめる.@n Contours Ring と Wings Ringの内容は保障される. @par 要求データ - ShortageWings Ring.CreateShortageWingsRing()で作成しても良い */ DllExport void JoinShortageWings(SOLID* solid) { if (solid->shortage_wings.empty()) return; // DEBUG_MODE print_messageln("Start JoinShortageWings"); BREP_WING_RING::iterator iwing; for (iwing=solid->shortage_wings.begin(); iwing!=solid->shortage_wings.end(); iwing++){ BREP_WING* wingA = (*iwing); if (BrepEdgeOtherWing(wingA)->contour==NULL) { // 両方NULL delete (wingA->edge); continue; } if (wingA->edge->edge_ring!=NULL) { BREP_EDGE_RING* edge_ring = wingA->edge->edge_ring; BREP_EDGE_RING::iterator iedge; for (iedge=edge_ring->begin(); iedge!=edge_ring->end(); iedge++){ if (wingA==(*iedge)->wing1 || wingA==(*iedge)->wing2) continue; if ((*iedge)->wing1->contour!=NULL && (*iedge)->wing2->contour!=NULL) continue; BREP_WING* wingB; if ((*iedge)->wing1->contour!=NULL) wingB = (*iedge)->wing1; else if ((*iedge)->wing2->contour!=NULL) wingB = (*iedge)->wing2; else continue; // 両方NULLをこちらが先に見つけた.→ 上のdeleteコードに任せる. if (wingA->vertex==wingB->vertex) { if (wingA->edge->wing1==wingA) wingA->edge->wing1 = wingB; else if (wingA->edge->wing2==wingA) wingA->edge->wing2 = wingB; if (wingB->edge->wing1==wingB) wingB->edge->wing1 = wingA; else if (wingB->edge->wing2==wingB) wingB->edge->wing2 = wingA; BREP_EDGE* sedge = wingB->edge; wingB->edge = wingA->edge; wingA->edge = sedge; wingB->edge->complete = true; wingA->edge->complete = false; break; } } } } CreateContoursRing(solid); CreateWingsRing(solid); // DEBUG_MODE print_messageln("End JoinShortageWings"); return; } //-------------------------------------------------------------------------------------------- /** DllExport int DupEdgeNumber(CONTOUR* contour) Contourの多重Edgeの数を数える. */ DllExport int DupEdgeNumber(CONTOUR* contour) { contour->dup_edge = 0; BREP_WING* first = contour->wing; if (first!=NULL) { BREP_WING* next = first; do { BREP_WING* wing = next; next = wing->next; if (wing->edge->edge_ring!=NULL) contour->dup_edge++; } while(next!=first); } return contour->dup_edge; } /** DllExport CONTOUR* CreateContourByVector(FACE* face, VECTOR* vector, bool special) Face と Vector[3] から Contour を作る. vector[0]〜vector[2] は3点の位置ベクトル(順序付けされている) */ DllExport CONTOUR* CreateContourByVector(FACE* face, VECTOR* vector, bool special) { SOLID* solid; CONTOUR* contour; VERTEX* vertex[3]; solid = (SOLID*)(face->shell->solid); // Vertex の生成 for (int i=0; i<3; i++) { vertex[i] = new VERTEX(); vertex[i]->point = vector[i]; vertex[i]->DataCloseCallback(); } // Vertexをソリッドの Octreeに登録 VERTEX* vert; for (int i=0; i<3; i++) { vert = (VERTEX*)AddVertex2Octree((BREP_VERTEX*)vertex[i], solid->octree); if (vert==NULL || vert!=vertex[i]) { delete vertex[i]; vertex[i] = vert; } } // vertex[0] = (VERTEX*)AddVertex2Octree((BREP_VERTEX*)vertex[0], solid->octree); // vertex[1] = (VERTEX*)AddVertex2Octree((BREP_VERTEX*)vertex[1], solid->octree); // vertex[2] = (VERTEX*)AddVertex2Octree((BREP_VERTEX*)vertex[2], solid->octree); // 法線ベクトルの計算 // normal.x = v[0].y*v[1].z-v[0].z*v[1].y+v[1].y*v[2].z-v[1].z*v[2].y+v[2].y*v[0].z-v[2].z*v[0].y; // normal.y = v[0].z*v[1].x-v[0].x*v[1].z+v[1].z*v[2].x-v[1].x*v[2].z+v[2].z*v[0].x-v[2].x*v[0].z; // normal.z = v[0].x*v[1].y-v[0].y*v[1].x+v[1].x*v[2].y-v[1].y*v[2].x+v[2].x*v[0].y-v[2].y*v[0].x; // normal.Normalize(); // ↑ここでは法線ベクトルは無視する. contour = CreateContourByVertex(face, vertex, special); return contour; } /** DllExport CONTOUR* CreateContourByVertex(FACE* face, VERTEX** vertex, bool special) Face と Vertex[3] から Vertex を作る. vertex[0]〜vertex[2] は3点の Vertex(順序付けされている) */ DllExport CONTOUR* CreateContourByVertex(FACE* face, VERTEX** vertex, bool special) { // 同じ点がある. if (vertex[0]==vertex[1] || vertex[1]==vertex[2] || vertex[0]==vertex[2]) { return NULL; } // 3点が直線上にある. if (!special) if (IsForbiddenEdge(vertex)) return NULL; CONTOUR* contour = new CONTOUR(face); // Wingを作る. BREP_WING* wing = contour->CreateWing((BREP_VERTEX*)vertex[0], (BREP_VERTEX*)vertex[1]); if (wing!=NULL) wing = contour->CreateWing((BREP_VERTEX*)vertex[1], (BREP_VERTEX*)vertex[2]); if (wing!=NULL) wing = contour->CreateWing((BREP_VERTEX*)vertex[2], (BREP_VERTEX*)vertex[0]); if (wing!=NULL) { contour->DataCloseCallback(); // 法線ベクトルを計算. } else { delete(contour); contour = NULL; } return contour; } /** DllExport bool IsIncludeCompleteEdge(BREP_WING* wing) Wingに関連したEdge及びその多重Edgeは完全か? @n そこにあるEdgeの内,最低一つは閉じているか? */ DllExport bool IsIncludeCompleteEdge(BREP_WING* wing) { EDGE* edge = (EDGE*)(wing->edge); if (edge->complete) return true; if (edge->edge_ring!=NULL) { BREP_EDGE_RING::iterator iedge; for (iedge=edge->edge_ring->begin(); iedge!=edge->edge_ring->end(); iedge++){ if ((*iedge)->complete) return true; } } return false; } /** DllExport void FastDeleteFace(FACE* face) 直前に生成した Faceを高速に削除する. 直前に生成したものでない Faceを指定した場合は誤作動する.@n Faceの数が多い場合,delete(Face) または ~BREP_FACE()を実行すると一々find()を呼び出すので時間が掛かる. */ DllExport void FastDeleteFace(FACE* face) { if (face==NULL) return; if (face->shell!=NULL) { face->shell->faces.pop_back(); face->shell = NULL; } // Destroy its contours BREP_CONTOUR* bpcn; BREP_CONTOUR_RING::iterator contour = face->outer_contours.begin(); while (contour!=face->outer_contours.end()) { bpcn = *contour; contour = face->outer_contours.erase(contour); bpcn->face = NULL; delete (bpcn); } free(face); return; } /** DllExport void SetDeletableContoursByEdge(EDGE* edge) Edgeに関連付けられた Contourに削除可能のマークをつける.削除は行わない. */ DllExport void SetDeletableContoursByEdge(EDGE* edge) { if (edge->edge_ring!=NULL) { BREP_EDGE_RING::iterator iedge; for (iedge=edge->edge_ring->begin(); iedge!=edge->edge_ring->end(); iedge++){ if ((*iedge)->wing1->contour!=NULL) { ((FACE*)((*iedge)->wing1->contour->face))->deletable = true; } if ((*iedge)->wing2->contour!=NULL) { ((FACE*)((*iedge)->wing2->contour->face))->deletable = true; } } } else { if (edge->wing1->contour!=NULL) { ((FACE*)(edge->wing1->contour->face))->deletable = true; } if (edge->wing2->contour!=NULL) { ((FACE*)(edge->wing2->contour->face))->deletable = true; } } } //---------------------------------------------------------------------------------------------- /* DllExport int IsAtLine(VERTEX** v) 3点 *v[0], *v[1], *v[2] が一直線上にあるかどうかを調べる. @attention toleranceの計算は再考が必要か? */ DllExport int IsAtLine(VERTEX** v) { TVECTOR vect = ToTVector(v[0]); TVECTOR vect1 = ToTVector(v[1]); TVECTOR vect2 = ToTVector(v[2]) - vect; TVECTOR vect3 = ToTVector(v[2]) - vect1; vect1 = vect1 - vect; int mode = 0; double tt; double th = ProportionVector(vect2, vect1, tt); tt = Max(tt, Zero_Eps); if (th>1.-tt) mode = 1; // 0->1->2 else { th = ProportionVector(vect1, vect2, tt); tt = Max(tt, Zero_Eps); if (th>1.-tt) mode = 2; // 0->2->1 else { th = ProportionVector(vect3, vect2, tt); tt = Max(tt, Zero_Eps); if (th>1.-tt) mode = 3; // 1->0->2 } } return mode; } /** DllExport bool IsForbiddenEdge(VERTEX** vert) Vertex vert[0]〜vert[2] が一直線に並んでいるか調べる.@n 一直線の場合は,該当Edgeを禁止する.また,既にその Edgeがある場合は関連 Contourを削除する. */ DllExport bool IsForbiddenEdge(VERTEX** vert) { EDGE* edge = NULL; int mode = IsAtLine(vert); if (mode==1) { // 0->1->2 if (vert[0]->forbidden_ring==NULL) vert[0]->forbidden_ring = new BREP_VERTEX_RING(); if (vert[2]->forbidden_ring==NULL) vert[2]->forbidden_ring = new BREP_VERTEX_RING(); vert[0]->forbidden_ring->push_back(vert[2]); vert[2]->forbidden_ring->push_back(vert[0]); edge = (EDGE*)BrepFindEdge(vert[0], vert[2]); } else if (mode==2) { // 0->2->1 if (vert[0]->forbidden_ring==NULL) vert[0]->forbidden_ring = new BREP_VERTEX_RING(); if (vert[1]->forbidden_ring==NULL) vert[1]->forbidden_ring = new BREP_VERTEX_RING(); vert[0]->forbidden_ring->push_back(vert[1]); vert[1]->forbidden_ring->push_back(vert[0]); edge = (EDGE*)BrepFindEdge(vert[0], vert[1]); } else if (mode==3) { // 2->0->1 if (vert[1]->forbidden_ring==NULL) vert[1]->forbidden_ring = new BREP_VERTEX_RING(); if (vert[2]->forbidden_ring==NULL) vert[2]->forbidden_ring = new BREP_VERTEX_RING(); vert[1]->forbidden_ring->push_back(vert[2]); vert[2]->forbidden_ring->push_back(vert[1]); edge = (EDGE*)BrepFindEdge(vert[1], vert[2]); } if (edge!=NULL) SetDeletableContoursByEdge(edge); if (mode==0) return false; return true; } //---------------------------------------------------------------------------------------------- /** DllExport bool IsCollisionContours(SOLID* solid, CONTOUR* contour, CONTOUR** collision) Contour が他の Contourと衝突しているかどうかをチェックする. @note 高速化しないと.... */ DllExport bool IsCollisionContours(SOLID* solid, CONTOUR* contour, CONTOUR** collision) { *collision = NULL; BREP_CONTOUR_RING::iterator icon; for (icon=solid->contours.begin(); icon!=solid->contours.end(); icon++){ if (!disJunctBounds(contour->face->rbound, (*icon)->face->rbound)) { if (!((FACE*)((*icon)->face))->deletable || ((FACE*)((*icon)->face))->initdata) { //if (contour!=(*icontour)) { int svrtx = CommonVertex((CONTOUR*)(*icon), contour); if (svrtx==3) { *collision = (CONTOUR*)(*icon); return true; } int lineno; if (SamePlaneContour((CONTOUR*)(*icon), contour, lineno)) { // 3角形の内部点 if (!contour->hasCollisionVector) contour->ComputeDirectRS(); if (IsInTriangle((CONTOUR*)(*icon), contour)) { *collision = (CONTOUR*)(*icon); return true; } if (!((CONTOUR*)(*icon))->hasCollisionVector) ((CONTOUR*)(*icon))->ComputeDirectRS(); if (IsInTriangle(contour, (CONTOUR*)(*icon))) { *collision = (CONTOUR*)(*icon); return true; } // 2D衝突検査 if (CollisionTriContour2D((CONTOUR*)(*icon), contour)) { *collision = (CONTOUR*)(*icon); return true; } } else { if (lineno==1) continue; // 3D衝突検査 if (!contour->hasCollisionVector) contour->ComputeDirectRS(); if (CollisionTriContour3D((CONTOUR*)(*icon), contour)) { *collision = (CONTOUR*)(*icon); return true; } if (!((CONTOUR*)(*icon))->hasCollisionVector) ((CONTOUR*)(*icon))->ComputeDirectRS(); if (CollisionTriContour3D(contour, (CONTOUR*)(*icon))) { *collision = (CONTOUR*)(*icon); return true; } } // } } } } return false; } /** DllExport bool CollisionTriContour3D(CONTOUR* contour1, CONTOUR* contour2) contour1と contour2が衝突しているかどうかをチェックする.@n contour2->directRS, directR, directS が予め計算されていなければならない.→例えば ComputeDirectRS() を使用 */ DllExport bool CollisionTriContour3D(CONTOUR* contour1, CONTOUR* contour2) { double tc, uc, vc, tm, um, ut, vt, tt, tmt, umt; BREP_WING* wing = contour1->wing; TVECTOR directR = contour2->directR; TVECTOR directS = contour2->directS; TVECTOR directRS = contour2->directRS; TVECTOR directT; TVECTOR directB; TVECTOR directQB; TVECTOR directN; // 各辺による衝突検出 for (int i=0; i<3; i++) { TVECTOR point = ToTVector((VERTEX*)(wing->vertex)); TVECTOR directQ = ToTVector((VERTEX*)(contour2->wing->vertex)) - point; for (int j=0; j<2; j++) { directN = ToTVector((VERTEX*)(wing->next->vertex)); if (j==0) directB = directN - point; else directB = directB + (ToTVector((VERTEX*)(wing->next->next->vertex)) - directN)*0.5; directQB = directQ^directB; um = directRS*directB; tm = directQB*directS; umt = TVectorMultiTolerance(directRS, directB); tmt = TVectorMultiTolerance(directQB, directS); if (Xabs(um)>Max(umt, Zero_Eps) && Xabs(tm)>Max(tmt, Zero_Eps)) { uc = tm; tc = -directQB*directR; vc = directRS*directQ; ut = tmt; tt = TVectorMultiTolerance(directQB, directR); vt = TVectorMultiTolerance(directRS, directQ); ut = Max(Collision_Tolerance, (um*ut+umt*uc)/(um*um)); tt = Max(Collision_Tolerance, (tm*tt+tmt*tc)/(tm*tm)); vt = Max(Collision_Tolerance, (um*vt+umt*vc)/(um*um)); uc = uc/um; tc = tc/tm; vc = vc/um; directT = directR + tc*directS; if (uc>ut && 1.-uc>ut && tc>tt && 1.-tc>tt && vc>vt && 1.-vc>vt && uc*directT.n>directT.t && (1.-uc)*directT.n>directT.t && tc*directS.n>directS.t && (1.-tc)*directS.n>directS.t && vc*directB.n>directB.t && (1.-vc)*directB.n>directB.t) { /**/ // DEBUG_MODE print_messageln("3D衝突 %d !!!! %e %e %e", j+1, uc, tc, vc); // PrintFacetAsciiSTL(contour1); // PrintFacetAsciiSTL(contour2); return true; } } } wing = wing->next; } return false; } DllExport bool CollisionTriContour2D(CONTOUR* contour1, CONTOUR* contour2) { double uc, vc, tm, um, ut, vt, tmt, umt; BREP_WING* wing = contour1->wing; TVECTOR directR = contour2->directR; TVECTOR directS = contour2->directS; TVECTOR directRS = contour2->directRS; wing = contour1->wing; for (int i=0; i<3; i++) { TVECTOR point = ToTVector((VERTEX*)(wing->vertex)); TVECTOR directB = ToTVector((VERTEX*)(wing->next->vertex)) - point; TVECTOR directQ = ToTVector((VERTEX*)(contour2->wing->vertex)) - point; TVECTOR directQB = directQ^directB; directB.norm(); tm = directQB*directS; um = directRS*directB; tmt = TVectorMultiTolerance(directQB, directS); umt = TVectorMultiTolerance(directRS, directB); if (Xabs(tm)<=Max(tmt, Zero_Eps) || Xabs(um)<=Max(umt, Zero_Eps)) { TVECTOR directBR = directB^directR; TVECTOR directQR = directQ^directR; TVECTOR directQB = directQ^directB; uc = ProportionVector(directQB, directBR, ut); vc = ProportionVector(directQR, directBR, vt); ut = Max(ut, Collision_Tolerance); vt = Max(vt, Collision_Tolerance); if (uc>ut && 1.-uc>ut && vc>vt && 1.-vc>vt && uc*directR.n>directR.t && (1.-uc)*directR.n>directR.t && vc*directB.n>directB.t && (1.-vc)*directB.n>directB.t) { /**/ // DEBUG_MODE print_messageln("同一平面上1 %e %e %e %e", uc, vc, ut, vt); // PrintFacetAsciiSTL(contour1); // PrintFacetAsciiSTL(contour2); return true; } directBR = directB^directS; directQR = (directQ+directR)^directS; directQB = (directQ+directR)^directB; uc = ProportionVector(directQB, directBR, ut); vc = ProportionVector(directQR, directBR, vt); ut = Max(ut, Collision_Tolerance); vt = Max(vt, Collision_Tolerance); if (uc>ut && 1.-uc>ut && vc>vt && 1.-vc>vt && uc*directS.n>directS.t && (1.-uc)*directS.n>directS.t && vc*directB.n>directB.t && (1.-vc)*directB.n>directB.t) { /**/ // DEBUG_MODE print_messageln("同一平面上2 %e %e %e %e", uc, vc, ut, vt); // PrintFacetAsciiSTL(contour1); // PrintFacetAsciiSTL(contour2); return true; } TVECTOR directT = directR + directS; directBR = directB^directT; directQR = directQ^directT; directQB = directQ^directB; uc = ProportionVector(directQB, directBR, ut); vc = ProportionVector(directQR, directBR, vt); ut = Max(ut, Collision_Tolerance); vt = Max(vt, Collision_Tolerance); if (uc>ut && 1.-uc>ut && vc>vt && 1.-vc>vt && uc*directT.n>directT.t && (1.-uc)*directT.n>directT.t && vc*directB.n>directB.t && (1.-vc)*directB.n>directB.t) { /**/ // DEBUG_MODE print_messageln("同一平面上3 %e %e %e %e", uc, vc, ut, vt); // PrintFacetAsciiSTL(contour1); // PrintFacetAsciiSTL(contour2); return true; } } wing = wing->next; } return false; } DllExport bool IsInTriangle(CONTOUR* contour1, CONTOUR* contour2) { double tc, uc, tt, ut; TVECTOR directS = contour2->directS; TVECTOR directRS = contour2->directRS; TVECTOR directQ, directT, directN; BREP_WING* wing = contour1->wing; for (int i=0; i<3; i++) { for (int j=0; j<2; j++) { directN = ToTVector((VERTEX*)(wing->vertex)); if (j==0) directQ = ToTVector((VERTEX*)(contour2->wing->vertex)) - directN; else directQ = directQ - (ToTVector((VERTEX*)(wing->next->vertex)) - directN)*0.5; TVECTOR directSQ = directS^directQ; TVECTOR directQR = directQ^contour2->directR; tc = ProportionVector(directQR, directSQ, tt); uc = ProportionVector(directSQ, directRS, ut); directT = contour2->directR + tc*directS; ut = Max(ut, Collision_Tolerance); tt = Max(tt, Collision_Tolerance); if (tc>tt && 1.-tc>tt && uc>ut && 1.-uc>ut && tc*directS.n>directS.t && (1.-tc)*directS.n>directS.t && uc*directT.n>directT.t && (1.-uc)*directT.n>directT.t) { // DEBUG_MODE print_messageln("三角形の内部 %d : %e %e %e %e", j+1, tc, uc, tt, ut); //PrintFacetAsciiSTL(contour1); //PrintFacetAsciiSTL(contour2); return true; } } } return false; } DllExport bool SamePlaneContour(CONTOUR* contour1, CONTOUR* contour2, int& lineno) { double um, umt, tm, tmt; BREP_WING* wing = contour1->wing; TVECTOR directB, directQ; lineno = 0; for (int i=0; i<3; i++) { directB = ToTVector((VERTEX*)(wing->next->vertex)) - ToTVector((VERTEX*)(wing->vertex)); directQ = ToTVector((VERTEX*)(contour2->wing->vertex)) - ToTVector((VERTEX*)(wing->vertex)); um = contour2->directRS*directB; tm = contour2->directRS*directQ; umt = TVectorMultiTolerance(contour2->directRS, directB); tmt = TVectorMultiTolerance(contour2->directRS, directQ); if (Xabs(um)=2) return true; return false; } DllExport int CommonVertex(CONTOUR* contour1, CONTOUR* contour2) { BREP_VERTEX_RING vertex_ring; int cnt = 0; BREP_WING* wing1 = contour1->wing; for (int i=0; i<3; i++) { bool common = false; BREP_WING* wing2 = contour2->wing; for (int j=0; j<3; j++) { if (wing1->vertex==wing2->vertex) { cnt++; common = true; break; } wing2 = wing2->next; } if (!common) vertex_ring.push_back(wing1->vertex); wing1 = wing1->next; } return cnt; } DllExport TVector ToTVector(BREP_VERTEX* v) { TVector tv; tv.x = v->point.x; tv.y = v->point.y; tv.z = v->point.z; tv.n = sqrt(tv.x*tv.x + tv.y*tv.y + tv.z*tv.z); tv.t = v->tolerance; return tv; } /** unsigned int CreateSolidFromSTL(STLData* stldata, unsigned int fno, SOLID* solid, bool collision, bool special) STLDataから SOLIDを生成する.SOLIDに使用された有効なファセットの数を返す. カウンタ使用可能. @param stldata STLデータへのポインタ @param fno Face の数 @param solid ソリッドデータへのポインタ @param collision 衝突判定を行うか? @b true 行う.@b false 行わない @param special 読み込みデータを特別扱いにするか? 特別扱いにした場合,不正読み込みデータを削除する. @b true する.@b false しない. @retval -1 ソリッドがNULL,またはソリッドの Octreeが NULL @retval -3 操作がキャンセルされた. */ DllExport int CreateSolidFromSTL(STLData* stldata, int fno, SOLID* solid, bool collision, bool special) { SHELL* shell; FACE* face; CONTOUR* contour; CVCounter* counter = NULL; VECTOR v[4]; if (solid==NULL) { DEBUG_MODE print_messageln("CreateSolidFromSTL: ソリッドへのポインタが NULLです."); return -1; } if (solid->octree==NULL) { DEBUG_MODE print_messageln("CreateSolidFromSTL: Solid のOctreeへのポインタがNULLです."); return -1; } solid->contours.clear(); // カウンタ int intvl = 1; if (solid->counter!=NULL) { counter = solid->counter->GetUsableCounter(); if (counter!=NULL) { counter->SetMax(100); if (special) counter->ResetRate(80, 100); intvl = Max(1, fno/100); //if (special) counter->ResetRate( 80, fno/COUNTER_RATE); //else counter->ResetRate(100, fno/COUNTER_RATE); } } shell = new SHELL(solid); for (int i=0; iDataCloseCallback(); if (!IsCollisionContours(solid, contour, &collision)) { solid->contours.push_back(contour); // IsCollisionContours()用 } else { ((FACE*)(collision->face))->deletable = true; // 衝突相手も消す. FastDeleteFace(face); } } else solid->contours.push_back(contour); } else { //FastDeleteFace(face); // ここでは,Face と Contourは1対1なので.// Debug の構成でエラーがでる. deleteNull(face); // 中身は空だから delete でいい? } if (counter!=NULL && i%intvl==0) { counter->StepIt(); if (counter->isCanceled()) { deleteNull(face); return -3; } } } if (counter!=NULL) counter->PutFill(); // IsForbiddenEdge()によって deletableになっているContourがあるかもしれないので, // CreateContoursRing()で作り直し. CreateContoursRing(solid); CreateWingsRing(solid); if (special) { // 初期データ(読み込みデータ)を特別扱いにする. // ここで,不必要なデータを削除する. // 多重Edgeの削除 CreateSurplusContoursRing(solid); if (counter!=NULL) counter->MakeChildCounter(10); DeleteSurplusContours(solid); if (counter!=NULL) counter->DeleteChildCounter(); // 直線に並んだ Edgeの削除 CreateShortageWingsRing(solid); if (counter!=NULL) counter->MakeChildCounter(10); DeleteStraightEdges(solid); if (counter!=NULL) counter->DeleteChildCounter(); // 残りは絶対削除させない. BREP_CONTOUR_RING::iterator icon; for (icon=solid->contours.begin(); icon!=solid->contours.end(); icon++) { ((FACE*)((*icon)->face))->initdata = true; //FacetAsciiData((CONTOUR*)(*icontour)); } } // delete(counter); CreateSurplusContoursRing(solid); CreateShortageWingsRing(solid); solid->DataCloseCallback(); return (int)solid->contours.size(); } DllExport bool IsConnectEdges(BREP_WING* wing1, BREP_WING* wing2) { if (BrepEdgeOtherWing(wing1)->vertex==wing2->vertex) return true; return false; }