/** @brief BREP ライブリラリ @file Brep.cpp @version @author modified by Fumi.Iseki @par ライセンス LGPL. http://breplibrary.sourceforge.net/ の BRLを改造 @note 平面の方程式 N・P+d = 0 (N:法線ベクトル,P:平面の点の位置ベクトル,d:定数,原点から平面への距離x-1) */ #include "Brep.h" using namespace jbxl; int OctreeNode_DelCount = 0; /********************************* BREP_SOLID *********************************/ /** BREP_SOLID::BREP_SOLID() 空の Solidを作る */ BREP_SOLID::BREP_SOLID() { facetno = 0; vertexno = 0; counter = NULL; octree = new OctreeNode((BREP_VERTEX*)NULL, this); rbound.set(HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL); } /** BREP_SOLID::~BREP_SOLID() ディストラクタ,Solid が持つ Shell以下のオブジェクトとVertex の Octreeを全て削除 */ BREP_SOLID::~BREP_SOLID() { BREP_SHELL* pbsh; BREP_SHELL_RING::iterator ishell = shells.begin(); int shn = shells.size(); CVCounter* cnt = NULL; if (counter!=NULL) { cnt = counter->GetUsableCounter(); if (cnt!=NULL) cnt->SetMax(100); } while (ishell!=shells.end()) { if (cnt!=NULL) cnt->MakeChildCounter(100/shn); pbsh = *ishell; ishell = shells.erase(ishell); // Shellの数は多くないはずなので,counter処理のために delete pbsh; // eraseの空処理を Shellに行わせる if (cnt!=NULL) cnt->DeleteChildCounter(); } delete octree; // DEBUG_MODE print_messageln("VERTEX = %d", OctreeNode_DelCount); OctreeNode_DelCount = 0; } /** void BREP_SOLID::DataCloseCallback() */ void BREP_SOLID::DataCloseCallback() { BREP_SHELL_RING::iterator ishell; for (ishell=shells.begin(); ishell!=shells.end(); ishell++) (*ishell)->DataCloseCallback(); for (ishell=shells.begin(); ishell!=shells.end(); ishell++) rbound.fusion((*ishell)->rbound); octree->Iterate(ComputeVertexNormal); } /** void BREP_SOLID::ConnectShell(BREP_SHELL* shell) Solidに指定したShellを結合する. */ // [copy from BRL] void BREP_SOLID::ConnectShell(BREP_SHELL* shell) { shell->solid = this; shells.push_back(shell); } /** void BREP_SOLID::DisconnectShell(BREP_SHELL* shell) Solidから指定したShellを削除する. */ void BREP_SOLID::DisconnectShell(BREP_SHELL* shell) { BREP_SHELL_RING::iterator ishell; ishell = std::find(shells.begin(), shells.end(), shell); if (ishell!=shells.end()) shells.erase(ishell); shell->solid = NULL; } /********************************* BREP_SHELL *********************************/ BREP_SHELL::BREP_SHELL(BREP_SOLID* pr_solid) { solid = pr_solid; rbound.set(HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL); if (solid!=NULL) solid->ConnectShell(this); } BREP_SHELL::~BREP_SHELL() { CVCounter* counter = NULL; if (solid!=NULL) { if (solid->counter!=NULL) { counter = solid->counter->GetUsableCounter(); if (counter!=NULL) counter->SetMax(100); } solid->DisconnectShell(this); } // Faces の破棄 BREP_FACE* pbfc; BREP_FACE_RING::iterator iface = faces.begin(); int cnt = 0; int itv = Max(1, (int)faces.size()/100); while (iface!=faces.end()) { pbfc = *iface; iface = faces.erase(iface); pbfc->shell = NULL; delete(pbfc); cnt++; // カウンタ処理 if (counter!=NULL && cnt%itv==0) counter->StepIt(); } // DEBUG_MODE print_messageln("FACET = %d", cnt); } void BREP_SHELL::DataCloseCallback() { BREP_FACE_RING::iterator iface; for (iface=faces.begin(); iface!=faces.end(); iface++) (*iface)->DataCloseCallback(); for (iface=faces.begin(); iface!=faces.end(); iface++) rbound.fusion((*iface)->rbound); } // // [copy] void BREP_SHELL::ConnectFace(BREP_FACE* face) { faces.push_back(face); } // // [copy] void BREP_SHELL::DisconnectFace(BREP_FACE* face) { BREP_FACE_RING::iterator iface; iface = std::find(faces.begin(), faces.end(), face); if (iface!=faces.end()) faces.erase(iface); face->shell = NULL; } /********************************* BREP_FACE *********************************/ BREP_FACE::BREP_FACE(BREP_SHELL* pr_shell) { shell = pr_shell; if (shell!=NULL) shell->ConnectFace(this); tolerance = Face_Tolerance; rbound.set(HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL); } BREP_FACE::~BREP_FACE() { if (shell!=NULL) shell->DisconnectFace(this); BREP_CONTOUR* bpcn; BREP_CONTOUR_RING::iterator icon = outer_contours.begin(); while (icon!=outer_contours.end()) { bpcn = *icon; icon = outer_contours.erase(icon); bpcn->face = NULL; delete (bpcn); } } void BREP_FACE::DataCloseCallback() { BREP_CONTOUR_RING::iterator icon; for (icon=outer_contours.begin(); icon!=outer_contours.end(); icon++) (*icon)->DataCloseCallback(); ComputePlaneEquation(); } // // [copy] void BREP_FACE::ConnectContour(BREP_CONTOUR* contour) { if (contour!=NULL) outer_contours.push_back(contour); } void BREP_FACE::DisconnectContour(BREP_CONTOUR* contour) { BREP_CONTOUR_RING::iterator icon; icon = std::find(outer_contours.begin(), outer_contours.end(), contour); if (icon!=outer_contours.end()) outer_contours.erase(icon); contour->face = NULL; } // [copy] static BREP_FACE* this_face; static double dmin, dmax, emax; // // [copy] void FaceClose(BREP_VERTEX *vertex) { double d = -(this_face->normal * vertex->point); if (d < dmin) dmin = d; if (d > dmax) dmax = d; if (vertex->tolerance>emax) emax = vertex->tolerance; this_face->rbound.fusion(vertex->point); } // // [copy] void BREP_FACE::ComputePlaneEquation() { this_face = this; normal = outer_contours.front()->normal; emax = 0.0; dmin = HUGE_VAL; dmax = -HUGE_VAL; BREP_CONTOUR_RING::iterator icon; for (icon=outer_contours.begin(); icon!=outer_contours.end(); icon++) (*icon)->IterateVertices(FaceClose); d = (dmin + dmax)/2.; tolerance = Max((dmax - dmin)/2., Face_Tolerance); tolerance = Max(emax, tolerance); double extent = tolerance + emax; rbound.xmin -= extent; rbound.ymin -= extent; rbound.zmin -= extent; rbound.xmax += extent; rbound.ymax += extent; rbound.zmax += extent; } /********************************* BREP_CONTOUR *********************************/ BREP_CONTOUR::BREP_CONTOUR(BREP_FACE* pr_face) { face = pr_face; if (face!=NULL) face->ConnectContour(this); rbound.set(HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL, HUGE_VAL, -HUGE_VAL); wing = NULL; // normal = VECTOR(0.0, 0.0, 0.0); dup_edge = 0; } // // [copy] BREP_CONTOUR::~BREP_CONTOUR() { if (face!=NULL) face->DisconnectContour(this); DestroyWings(); } void BREP_CONTOUR::DataCloseCallback() { // if (normal.norm2()==0.0) ComputeNormal(); ComputeNormal(); } /** void BREP_CONTOUR::ConnectWing(BREP_WING* new_wing) 新しい Wingを Contourのリストに追加する. */ // [copy] void BREP_CONTOUR::ConnectWing(BREP_WING* new_wing) { new_wing->contour = this; if (wing==NULL) { // 最初の Wing new_wing->next = new_wing->prev = new_wing; wing = new_wing; } else { // 2番目以降の Wing new_wing->next = wing; new_wing->prev = wing->prev; new_wing->prev->next = new_wing->next->prev = new_wing; } } // // [copy] void BREP_CONTOUR::DisconnectWing(BREP_WING* dis_wing) { if (!wing->next || !wing->prev) { print_messageln("DisconnectWing: Wingがまだ不正に Contourと接続したままになっている!!"); } if (wing==dis_wing) { if (dis_wing->next == dis_wing) { wing = 0; } else { wing = dis_wing->next; } } if (dis_wing->next) dis_wing->next->prev = dis_wing->prev; if (dis_wing->prev) dis_wing->prev->next = dis_wing->next; dis_wing->contour = 0; dis_wing->next = dis_wing->prev = 0; } /** BREP_WING* BREP_CONTOUR::CreateWing(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) vertex1をスタートVertexとした,Contour,Vertexに関連付けられらたWingを作る(必要なら新しいEdgeも).@n 作成時,指定するVertexは順序付けられていなければエラーとなる. */ BREP_WING* BREP_CONTOUR::CreateWing(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) { // 新しく作成するWingのスタートVertexは,一つ前のWingのエンドVertexと同一でなければならない. // つまり Wingは順序よく作成しなければならない. if (wing!=NULL && BrepEdgeOtherWing(wing->prev)->vertex!=vertex1) { DEBUG_MODE print_messageln("CreateWing: Wingが順序良く作成されていない!!"); return 0; } // vertex1をスタートVertexとしたWingを作る.すでに空のWingがある場合にはそれを返す. // vertex1==vertex2 の場合は NULLを返す. BREP_WING* wing = BrepCreateWingWithoutContour(vertex1, vertex2); if (wing==NULL) return NULL; // Edgeのループ方向がおかしい // 現在の BrepCreateWingWithoutContour()の実装では起こりえないエラー if (wing->vertex != vertex1) { DEBUG_MODE print_messageln("CreateWing: Edgeのループ方向がおかしい(起こりえないエラー)!!"); return 0; } // WingをContourに登録 ConnectWing(wing); if (BrepEdgeOtherWing(wing)->contour!=NULL) { // 対応するEdgeは 2つの参照されたWingを持つ完全な Edge wing->edge->complete = true; } // WingをスタートVertexのリングに登録 (wing->vertex)->wing_ring.push_back(wing); return wing; } /** void BREP_CONTOUR::DestroyWings() Contourに関連付けられた Wingをすべて破棄する. */ // [copy] void BREP_CONTOUR::DestroyWings() { BREP_WING* first = wing; if (first==NULL) return; BREP_WING* prev; for (BREP_WING* swing=first->prev; swing!=first; swing=prev) { prev = swing->prev; BrepDestroyWing(swing); } BrepDestroyWing(first); } // // [copy] void BREP_CONTOUR::IterateWings(void (*func)(BREP_WING*)) { BREP_WING* first = wing; if (!first) return; BREP_WING* next = first; do { BREP_WING* swing = next; next = swing->next; func(swing); } while(next != first); } // // [copy] void BREP_CONTOUR::IterateVertices(void (*func)(BREP_VERTEX*)) { BREP_WING* first = wing; if (!first) return; BREP_WING* next = first; do { BREP_WING* swing = next; next = swing->next; func(swing->vertex); } while(next != first); } /** void BREP_CONTOUR::ComputeNormal() Newells method により法線ベクトルを計算する. */ void BREP_CONTOUR::ComputeNormal() { normal = VECTOR(0, 0, 0); VECTOR next = wing->vertex->point; for (BREP_WING* swing=wing; swing; swing=(swing->next==wing ? NULL:swing->next)) { VECTOR cur = next; next = swing->next->vertex->point; normal.x += (cur.y - next.y) * (cur.z + next.z); normal.y += (cur.z - next.z) * (cur.x + next.x); normal.z += (cur.x - next.x) * (cur.y + next.y); } normal.normalize(); } BREP_CONTOUR* CreateContour(BREP_FACE* face) { BREP_CONTOUR* contour = new BREP_CONTOUR(face); return contour; } /********************************* BREP_WING *********************************/ BREP_WING::BREP_WING(BREP_VERTEX* vx) { vertex = vx; prev = NULL; next = NULL; edge = NULL; contour = NULL; } /********************************* BREP_EDGE *********************************/ BREP_EDGE::BREP_EDGE(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) { wing1 = new BREP_WING(vertex1); wing2 = new BREP_WING(vertex2); wing1->edge = wing2->edge = this; center = (vertex1->point + vertex2->point)/2.; edge_ring = NULL; complete = false; tolerance = Edge_Tolerance; } BREP_EDGE::~BREP_EDGE() { if (wing1->contour || wing2->contour) { DEBUG_MODE print_messageln("~BREP_EDGE: この Edge はまだ Contourで使われている!!"); } delete wing1; delete wing2; if (edge_ring!=NULL) { BREP_EDGE_RING::iterator iedge = std::find(edge_ring->begin(), edge_ring->end(), this); if (iedge!=edge_ring->end()) { edge_ring->erase(iedge); } if (edge_ring->size()==1) { (*(edge_ring->begin()))->edge_ring = NULL; delete(edge_ring); } } } void BREP_EDGE::DataCloseCallback() { // M.Segal, SIGGRAPH '90 p105 double e = (wing1->vertex)->tolerance; e = Max(e, (wing2->vertex)->tolerance); tolerance = Max(e, tolerance); } /********************************* BREP_VERTEX *********************************/ BREP_VERTEX::BREP_VERTEX() { // normal = VECTOR(0, 0, 0); // point = VECTOR(0, 0, 0); tolerance = Abs_Vertex_Tolerance; // DEBUG_MODE print_messageln("TOL = %f", tolerance); } BREP_VERTEX::~BREP_VERTEX() { if (!wing_ring.empty()) DEBUG_MODE print_messageln("~BREP_VERTEX: Wingのリングがまだ空でない!!"); } // // [copy] void BREP_VERTEX::DisconnectWing(BREP_WING* wing) { BREP_WING_RING::iterator iwing; iwing = std::find(wing_ring.begin(), wing_ring.end(), wing); if (iwing==wing_ring.end()) { DEBUG_MODE print_messageln("DisconnectWing: この Wingは Vertexと接続していません!!"); return; } wing_ring.erase(iwing); } /* void BREP_VERTEX::ComputeNormal() Vertexの法線ベクトルを計算する.@n Vertexの周りの Contourの法線ベクトルの加算平均を計算する */ // [copy] void BREP_VERTEX::ComputeNormal() { normal = VECTOR(0.0, 0.0, 0.0); BREP_WING_RING::iterator iwing; for (iwing=wing_ring.begin(); iwing!=wing_ring.end(); iwing++) { BREP_WING* wing = *iwing; normal = normal + (wing->contour->face)->normal; } normal.normalize(); } void BREP_VERTEX::ComputeTolerance() { double max = Xabs(point.x); max = Max(max, Xabs(point.y)); max = Max(max, Xabs(point.z)); tolerance = Vertex_Tolerance * max; // 相対 tolerance = Max(tolerance, Abs_Vertex_Tolerance); // 絶対 } void BREP_VERTEX::DataCloseCallback() { ComputeTolerance(); } void BREP_VERTEX::IterateWings(void (*func)(BREP_WING*)) { BREP_WING_RING::iterator iwing; for (iwing=wing_ring.begin(); iwing!=wing_ring.end(); iwing++) func(*iwing); } /********************************* OctreeNode *********************************/ OctreeNode::OctreeNode(BREP_VERTEX* new_vertex, BREP_SOLID* sld/*=NULL*/) { solid = sld; vertex = new_vertex; for (int i=0; i<8; i++) child[i] = NULL; } OctreeNode::~OctreeNode() { for (int i=0; i<8; i++) { if (child[i]) delete child[i]; } delete vertex; OctreeNode_DelCount++; //if (solid!=NULL && OctreeNode_DelCount%COUNTER_RATE==0) { // if (solid->counter!=NULL) solid->counter->GetUsableCounter()->StepIt(); //} } /** OctreeNode* OctreeNode::AddWithUnique(BREP_VERTEX* new_vertex) Octreeに Vertex new_vertexそのものを登録する.登録した OctreeNodeを返す. ^^^^^^^^ 既に同じ位置のVertexが登録済みの場合は,その OctreeNodeを返す.@n AddWithDuplicates() とは戻り値が違うので注意する. */ OctreeNode* OctreeNode::AddWithUnique(BREP_VERTEX* new_vertex) { OctreeNode* o = NULL; OctreeNode* p = this; int cmp = -1; if (p->vertex==NULL) { // 一番最初の Vertex p->vertex = new_vertex; return p; } while (p!=NULL) { cmp = VertexCompare(p->vertex, new_vertex); if (cmp==8) { return p; // 既に同じ位置のVertexが登録済み } o = p; p = p->child[cmp]; } if (cmp>=0) { p = new OctreeNode(new_vertex, solid); if (o!=NULL) o->child[cmp] = p; } return p; } /** OctreeNode* OctreeNode::AddWithDuplicates(BREP_VERTEX* new_vertex) Octreeに Vertex new_vertex そのものを登録する.重複登録を許す.@n Octreeのトップのポインタを返す. */ OctreeNode* OctreeNode::AddWithDuplicates(BREP_VERTEX* new_vertex) { OctreeNode* o = NULL; OctreeNode* p = this; int cmp = -1; if (p->vertex==NULL) { // 一番最初の Vertex p->vertex = new_vertex; return p; } while (p!=NULL) { cmp = VertexCompare(p->vertex, new_vertex); o = p; p = p->child[cmp%8]; } if (cmp>=0) { p = new OctreeNode(new_vertex, solid); if (o!=NULL) o->child[cmp%8] = p; } return this; } /** OctreeNode* OctreeNode::FindSubtree(BREP_VERTEX* element) Vertex element と同じ位置にある Vertexを含むノードを返す. */ // [copy] OctreeNode* OctreeNode::FindSubtree(BREP_VERTEX* element) { OctreeNode* p = this; while(p!=NULL){ int cmp = VertexCompare(p->vertex, element); if (cmp==8) return p; if (cmp<0) return 0; p = p->child[cmp]; } return 0; } /** BREP_VERTEX* OctreeNode::Find(BREP_VERTEX* element) { Vertex element と同じ位置にある Vertexを返す. */ // [copy] BREP_VERTEX* OctreeNode::Find(BREP_VERTEX* element) { OctreeNode* p = FindSubtree(element); // 位置で探す if (p!=NULL) return p->vertex; return 0; } // // [copy] void OctreeNode::Iterate(void (*func)(BREP_VERTEX*)) { for (int i=0; i<8; i++) { if (child[i]) child[i]->Iterate(func); } func(vertex); } /********************************* Other Functions *********************************/ /** DllExport void BrepConnectWingToVertex(BREP_WING* wing) WingのスタートVertexのリングに,この Wingを登録する.@n Wingが実在する(使用されている)ためには,このリングに登録されてることと,Contourから(へ) リンクされることである. */ // [copy] //static void BrepConnectWingToVertex(BREP_WING* wing) DllExport void BrepConnectWingToVertex(BREP_WING* wing) { if (wing!=NULL) (wing->vertex)->wing_ring.push_back(wing); } /** DllExport BREP_WING* BrepCreateWingWithoutContour(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) vertex1をスタートVertexとしたWingを(必要ならEdgeも)作成して返す. Wingが作成された時点では,WingはContourには関連付けられていない. */ DllExport BREP_WING* BrepCreateWingWithoutContour(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) { BREP_WING *wing; // vertex1 - vertex2 間にエッジが既に登録されているかどうかチェックする. BREP_EDGE* edge = BrepFindEdge(vertex1, vertex2); if (edge==NULL) { // Edgeは存在しない. edge = CreateEdge(vertex1, vertex2); if (edge==NULL) return NULL; // vertex1==vertex2 なら NULL wing = edge->wing1; } else{ // Edgeは既に存在する. if (edge->wing1->vertex==vertex1) wing = edge->wing1; else if (edge->wing2->vertex==vertex1) wing = edge->wing2; else { // 起こりえないエラー DEBUG_MODE print_messageln("BrepCreateWingWithoutContour: 起こりえないエラー? その1."); return NULL; } // Wingが既に Contourで使われている場合,他の Wingを探す. if (edge->edge_ring!=NULL && wing->contour!=NULL) { BREP_EDGE_RING::iterator iedge=edge->edge_ring->begin(); while (iedge!=edge->edge_ring->end() && wing->contour!=NULL) { if ((*iedge)->wing1->vertex==vertex1) wing = (*iedge)->wing1; else if ((*iedge)->wing2->vertex==vertex1) wing = (*iedge)->wing2; else { // 起こりえないエラー DEBUG_MODE print_messageln("BrepCreateWingWithoutContour: 起こりえないエラー? その2."); return NULL; } iedge++; } } // このWingは既に Contourで使われているか? if (wing->contour!=NULL){ // 新しくEdgeを作り直す BREP_EDGE* new_edge = CreateEdge(vertex1, vertex2); if (new_edge==NULL) return NULL; if (edge->edge_ring==NULL) { edge->edge_ring = new BREP_EDGE_RING(); edge->edge_ring->push_back(edge); } edge->edge_ring->push_back(new_edge); new_edge->edge_ring = edge->edge_ring; wing = new_edge->wing1; } } return wing; } // [copy] DllExport void BrepDestroyWing(BREP_WING* wing) { wing->vertex->DisconnectWing(wing); wing->contour->DisconnectWing(wing); if (!wing->edge->wing1->contour && !wing->edge->wing2->contour) { delete wing->edge; } else { wing->edge->complete = false; } } /** DllExport BREP_EDGE* BrepFindEdge(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) vertex1と vertex2が既にエッジで結ばれているかどうかをチェックする. もし結ばれていれば,最初に見つけた Edgeを返す. @code vertex1--Wing1--Edge--Wing2--vertex2 @endcode */ // [copy] DllExport BREP_EDGE* BrepFindEdge(BREP_VERTEX* vertex1, BREP_VERTEX* vertex2) { BREP_WING_RING ring; BREP_WING_RING::iterator iwing; ring = vertex2->wing_ring; for (iwing=ring.begin(); iwing!=ring.end(); iwing++){ BREP_WING* wing = *iwing; if (BrepEdgeOtherWing(wing)->vertex==vertex1) return wing->edge; } ring = vertex1->wing_ring; for (iwing=ring.begin(); iwing!=ring.end(); iwing++) { BREP_WING* wing = *iwing; if (BrepEdgeOtherWing(wing)->vertex==vertex2) return wing->edge; } return 0; } /** DllExport BREP_VERTEX* AddVertex2Octree(BREP_VERTEX* vert, OctreeNode* octree) Vertex vert を octreeに一意的に登録する. 既に同じ位置に Vertexが登録されている場合は,vertは消去されて,既に登録されている Vertexが返される.@n この関数を使用後は vertを使用してはいけない(deleteされている可能性があるので) @par 使用例 @code vert = AddVertex2Octree(vert, octree); @endcode */ DllExport BREP_VERTEX* AddVertex2Octree(BREP_VERTEX* vert, OctreeNode* octree) { OctreeNode* node; node = octree->AddWithUnique(vert); if (node==NULL) { //delete vert; return NULL; } if (node->vertex==vert) { octree->solid->vertexno++; // Vertexを新規登録したのでカウントする. } // else { // delete vert; // 既に同じ位置のVertexが登録済み // } return node->vertex; } /* [copy] */ DllExport BREP_EDGE* CreateEdge(BREP_VERTEX* v1, BREP_VERTEX* v2) { if (v1==v2) return NULL; BREP_EDGE* edge = new BREP_EDGE(v1, v2); edge->DataCloseCallback(); return edge; } /* */ DllExport void ComputeVertexNormal(BREP_VERTEX* vert) { if (vert!=NULL) vert->ComputeNormal(); } /** DllExport int VertexCompare(BREP_VERTEX* v1, BREP_VERTEX* v2) v2 に対する v1 の位置を検査する. @retval 0〜7 Vertex の位置 @retval 8 同じVertex */ DllExport int VertexCompare(BREP_VERTEX* v1, BREP_VERTEX* v2) { double tolerance = v1->tolerance + v2->tolerance; double dist2 = (v1->point.x-v2->point.x)*(v1->point.x-v2->point.x) + (v1->point.y-v2->point.y)*(v1->point.y-v2->point.y) + (v1->point.z-v2->point.z)*(v1->point.z-v2->point.z); if (dist2<=tolerance*tolerance) return 8; int code = 0; if (v1->point.x > v2->point.x) code += 1; if (v1->point.y > v2->point.y) code += 2; if (v1->point.z > v2->point.z) code += 4; if (code != 0) return code; // x1 > x2 || y1 > y2 || z1 > z2 return 0; } /** DllExport BREP_WING* BrepEdgeOtherWing(BREP_WING* wing) Edgeに関連付けられたもう一方の Wing を返す. */ // [copy] DllExport BREP_WING* BrepEdgeOtherWing(BREP_WING* wing) { return (wing==wing->edge->wing1 ? wing->edge->wing2 : wing->edge->wing1); }