// Copyright (C) Mocchi (mocchi_2003@yahoo.co.jp) // License: Boost Software License See LICENSE.txt for the full license. #include "opennurbs.h" #include "ONGEO.h" #include <cstdio> #include <cstdlib> #include <cmath> #include <unordered_map> #include <windows.h> #ifdef max #undef max #endif #ifdef min #undef min #endif namespace std{ template<> struct hash<ON_2dex> { size_t operator() (const ON_2dex &data) const { hash<long long int> h; return h(static_cast<long long int>(data.j) * 4294967296LL + data.i); } }; template<> struct hash<ON_3dPoint> { size_t operator() (const ON_3dPoint &data) const { hash<double> h; return h(data.x + data.y * 10000 + data.z * 100000000); } }; } bool operator == (const ON_2dex &lhs, const ON_2dex &rhs){ return lhs.i == rhs.i && lhs.j == rhs.j; } // 指定ã•れ㟠mesh ã® func_height ã®å‡ºåЛ値(高ã•)㌠0 ã¨ãªã‚‹ä½ç½®ã«ã‚³ãƒ³ã‚¿ãƒ¼ã‚’生æˆã—〠ON_Polyline ã®é…列形å¼ã§å‡ºåŠ›ã™ã‚‹ã€‚ // func_height: 入力:é ‚ç‚¹ã‚¤ãƒ³ãƒ‡ãƒƒã‚¯ã‚¹ã€å‡ºåŠ›:高㕠ã¨ãªã‚‹é–¢æ•°ã€‚ template <typename F> void Mesh_CalculateContourPolylines(const ON_Mesh &mesh, ON_ClassArray<ON_Polyline> &contours, F &func_height){ ON_SimpleArray<ON_2dex> edges; mesh.GetMeshEdges(edges); ON_Interval hint; std::unordered_map<ON_2dex, ON_3dPoint> height_map; // func_height値ã§0を交差ã™ã‚‹ã‚¨ãƒƒã‚¸ã¨ã€ãã®ãƒ‘ラメータ値をheight_mapã«ä¿ç®¡ã™ã‚‹ã€‚ for (int i = 0; i < edges.Count(); ++i){ ON_2dex &edge = edges[i]; double hi = func_height(edge.i); double hj = func_height(edge.j); if (hi * hj > 0) continue; double t; if (hi == hj && hi == 0) t = 0.5; else{ hint.m_t[0] = hi; hint.m_t[1] = hj; t = hint.NormalizedParameterAt(0); } ON_3dPoint pt_s = mesh.Vertex(edge.i); ON_3dPoint pt_e = mesh.Vertex(edge.j); ON_3dPoint pt = (1 - t) * pt_s + t * pt_e; height_map.insert(std::make_pair(edge, pt)); } std::unordered_multimap<ON_3dPoint, ON_3dPoint> edgelines; // height_map ã«è¨˜éŒ²ã•れãŸã‚¨ãƒƒã‚¸ã‚’æŒã¤ face を探ã™ã€‚ // (face ã«ã¯è©²å½“ã™ã‚‹ã‚¨ãƒƒã‚¸ãŒé€šå¸¸2ã¤å˜åœ¨ã™ã‚‹ã¯ãš)。ãã®2ã¤ã®ã‚¨ãƒƒã‚¸ã®ãƒ‘ラメータ値ã‹ã‚‰æ±‚ã‚ãŸç‚¹ã‚’繋ã for (int j = 0; j < mesh.m_F.Count(); ++j){ const ON_MeshFace &f = mesh.m_F[j]; int iter_cnt = 0; ON_3dPoint edgeline_pt[2]; for (int i = 0; i < 4; ++i){ int vs = f.vi[i], ve = f.vi[(i+1)%4]; if (vs == ve) continue; if (vs > ve) std::swap(vs, ve); ON_2dex edge = {vs, ve}; auto iter = height_map.find(edge); if (iter == height_map.end()) continue; edgeline_pt[iter_cnt++] = iter->second; if (iter_cnt == 2) break; // Todo: 3ã¤ä»¥ä¸Šã‚ã‚‹å ´åˆ } if (iter_cnt != 2) continue; edgelines.insert(std::make_pair(edgeline_pt[0], edgeline_pt[1])); edgelines.insert(std::make_pair(edgeline_pt[1], edgeline_pt[0])); } #if 1 // edgelines を出æ¥ã‚‹é™ã‚Šç¹‹ã„ã§ Polyline ã¨ã—ã¦æ›¸ã出㙠while(edgelines.size()){ auto iter_b = edgelines.begin(); ON_3dPoint edgeline_pt[2] = {iter_b->first, iter_b->second}; edgelines.erase(iter_b); ON_Polyline &pol = contours.AppendNew(); pol.Append(edgeline_pt[0]); pol.Append(edgeline_pt[1]); // j = 0: 折れ線ã®çµ‚点å´ã‚’å»¶ã°ã™ãƒ«ãƒ¼ãƒ—〠j = 1: 折れ線ã®å§‹ç‚¹å´ã‚’å»¶ã°ã™ãƒ«ãƒ¼ãƒ— (折れ線ã®å‘ãã‚’å転ã•ã›ã¦åŒã˜å‡¦ç†ã‚’ã™ã‚‹) for (int j = 0; j < 2; ++j){ for (;;){ ON_3dPoint pt_next(ON_UNSET_VALUE, ON_UNSET_VALUE, ON_UNSET_VALUE); // 次ã®ã‚»ã‚°ãƒ¡ãƒ³ãƒˆã®çµ‚点 auto iter_range = edgelines.equal_range(edgeline_pt[1]); std::vector<decltype(iter_b)> iters_to_remove; // åŒã˜ã‚»ã‚°ãƒ¡ãƒ³ãƒˆã®å‘ãé•ã„(削除対象) // åŒã˜ã‚»ã‚°ãƒ¡ãƒ³ãƒˆã®å‘ãé•ã„ã¨æ¬¡ã®ã‚»ã‚°ãƒ¡ãƒ³ãƒˆã‚’探㙠for (auto iter = iter_range.first; iter != iter_range.second; ++iter){ if (iter->second == edgeline_pt[0]){ iters_to_remove.push_back(iter); }else if (pt_next.x == ON_UNSET_VALUE){ pt_next = iter->second; }else continue; } // åŒã˜ã‚»ã‚°ãƒ¡ãƒ³ãƒˆã®å‘ãé•ã„ã¯å‰Šé™¤ã™ã‚‹ã€‚ for (size_t i = 0; i < iters_to_remove.size(); ++i) edgelines.erase(iters_to_remove[i]); // 次ã®ã‚»ã‚°ãƒ¡ãƒ³ãƒˆãŒã‚ã£ãŸå ´åˆã¯ã€ã‚»ã‚°ãƒ¡ãƒ³ãƒˆæƒ…å ±ã‚’æ›´æ–°ã—ã¦æŠ˜ã‚Œç·šã‚’å»¶ã°ã™ã€‚ if (pt_next.x != ON_UNSET_VALUE){ pol.Append(pt_next); edgeline_pt[0] = edgeline_pt[1]; edgeline_pt[1] = pt_next; auto iter_range = edgelines.equal_range(edgeline_pt[0]); for (auto iter = iter_range.first; iter != iter_range.second; ++iter){ if (iter->second != edgeline_pt[1]) continue; edgelines.erase(iter); break; } }else break; } if (j == 0 && pol.Count() > 0){ iter_b = edgelines.find(pol[0]); if (iter_b != edgelines.end()){ edgeline_pt[0] = pol[0]; edgeline_pt[1] = iter_b->second; edgelines.erase(iter_b); pol.Reverse(); pol.Append(edgeline_pt[1]); } } } } #else // edgelines 一切繋ãŒãšã« Polyline ã¨ã—ã¦æ›¸ã出㙠for (auto iter = edgelines.begin(); iter != edgelines.end(); ++iter){ ON_Polyline &pol = contours.AppendNew(); pol.Append(iter->first); pol.Append(iter->second); } #endif } int main(int argc, char *argv[]){ if (argc < 2) return 0; ON_Mesh mesh; ON_String header; ONGEO_ReadBinarySTL(ON_BinaryFile(ON::read, ON_FileStream::Open(argv[1], "rb")), mesh, header); ON_BoundingBox bb; mesh.GetTightBoundingBox(bb); double y_mid = bb.Center().y; LARGE_INTEGER freq, count1, count2; ::QueryPerformanceFrequency(&freq); ::QueryPerformanceCounter(&count1); ON_ClassArray<ON_Polyline> contours; Mesh_CalculateContourPolylines(mesh, contours, [&](int vi){ return mesh.Vertex(vi).y - y_mid; }); ::QueryPerformanceCounter(&count2); std::printf("%f msec\n", static_cast<double>(count2.QuadPart - count1.QuadPart) * 1000.0 / static_cast<double>(freq.QuadPart)); ONX_Model model; ONX_Model_Object &obj_mesh = model.m_object_table.AppendNew(); obj_mesh.m_bDeleteObject = false; obj_mesh.m_object = &mesh; for (int i = 0; i < contours.Count(); ++i){ ON_PolylineCurve pc(contours[i]); ONX_Model_Object &obj_crv = model.m_object_table.AppendNew(); obj_crv.m_bDeleteObject = true; obj_crv.m_object = pc.Duplicate(); } model.Write("mesh_contour.3dm", 4); return 0; }