00001 // Copyright (c) 1998-2014 by Tech Soft 3D, Inc. 00002 // 00003 // The information contained herein is confidential and proprietary to Tech Soft 3D, Inc., 00004 // and considered a trade secret as defined under civil and criminal statutes. 00005 // Tech Soft 3D, Inc. shall pursue its civil and criminal remedies in the event of 00006 // unauthorized use or misappropriation of its trade secrets. Use of this information 00007 // by anyone other than authorized employees of Tech Soft 3D, Inc. is granted only under 00008 // a written non-disclosure agreement, expressly prescribing the scope and manner of such use. 00009 00010 #pragma once 00011 00012 00013 #ifdef HMFC_STATIC_LIB 00014 # error "Code cannot be statically linked." 00015 #endif 00016 00017 00018 #ifdef H_PACK_8 00019 # pragma pack(push) 00020 # pragma pack(8) 00021 #endif 00022 00023 00025 00026 00027 #include "HMutexOOC.h" 00028 #include "HSelectionSet.h" 00029 #include "HTManager.h" 00030 #include "HWindowFilterOOC.h" 00031 #include "PointCloudAPI.h" 00032 #include <map> 00033 #include <vector> 00034 00035 00037 00038 00039 #ifdef _WIN32 00040 # pragma warning(disable: 4127) 00041 #endif 00042 00043 00044 #ifndef ASSERT 00045 # ifdef NDEBUG 00046 # define ASSERT(x) do {} while (false) 00047 # else 00048 #if _WIN32 00049 # define ASSERT(x) ((!(x)) ? __debugbreak() : 1) 00050 #else 00051 # include <assert.h> 00052 # define ASSERT assert 00053 #endif 00054 # endif 00055 #endif 00056 00057 00059 00060 00061 class HSelectionSetHelperBaseOOC { 00062 protected: 00063 static HSelectionSet *& Instance () 00064 { 00065 static HSelectionSet * instance = nullptr; 00066 return instance; 00067 } 00068 }; 00069 00070 00076 template <typename SelectionSet> 00077 class HSelectionSetOOC : public SelectionSet, private HSelectionSetHelperBaseOOC, private HTClient { 00078 typedef HMutexOOC::LockGuard LockGuard; 00079 typedef void (HC_CDECL * CallbackFunc)(...); 00080 00081 private: 00082 enum CallbackType { 00083 CallbackType_Invalid, 00084 CallbackType_Populate, 00085 CallbackType_Deleted, 00086 }; 00087 00088 struct CallbackKeyInfo { 00089 public: 00090 CallbackKeyInfo () 00091 : type(CallbackType_Invalid) 00092 {} 00093 00094 CallbackKeyInfo (HC_KEY key, CallbackType type) 00095 : key(key) 00096 , type(type) 00097 { 00098 ASSERT(type != CallbackType_Invalid); 00099 } 00100 00101 public: 00102 HC_KEY key; 00103 CallbackType type; 00104 }; 00105 00106 private: 00107 HSelectionSetOOC (HBaseView & view, bool deep_select) 00108 : SelectionSet(&view) 00109 , HTClient(0.01f, HTCS_PeriodicSkip) 00110 , filter(deep_select) 00111 , callback_key_infos(new VArray<CallbackKeyInfo>()) 00112 { 00113 static bool callback_names_defined = false; 00114 00115 static_cast<HSelectionSet *>(static_cast<SelectionSet *>(this)); // Ensure SelectionSet is a valid base class (i.e. it derives from HSelectionSet). 00116 00117 { 00118 LockGuard lock(selection_mutex); 00119 00120 if (!callback_names_defined) { 00121 HC_Define_Callback_Name("ooc_selection_on_populate_key", reinterpret_cast<CallbackFunc>(StaticOnPopulateKey)); 00122 HC_Define_Callback_Name("ooc_selection_on_deleted_key", reinterpret_cast<CallbackFunc>(StaticOnDeletedKey)); 00123 callback_names_defined = true; 00124 } 00125 HC_Define_System_Options(H_FORMAT_TEXT("populate key callback = ooc_selection_on_populate_key")); 00126 HC_Define_System_Options(H_FORMAT_TEXT("deleted key callback = ooc_selection_on_deleted_key")); 00127 } 00128 00129 HDB::GetHTManager()->RegisterClient(this); 00130 } 00131 00132 ~HSelectionSetOOC () 00133 { 00134 LockGuard lock(selection_mutex); 00135 00136 HDB::GetHTManager()->UnRegisterClient(this); 00137 00138 HC_Define_System_Options("no populate key callback"); 00139 HC_Define_System_Options("no deleted key callback"); 00140 00141 Reset(); 00142 delete callback_key_infos; 00143 00144 Instance() = nullptr; 00145 } 00146 00147 public: 00154 static HSelectionSetOOC * CreateInstance (HBaseView & view, bool deep_select) 00155 { 00156 HSelectionSet *& instance = Instance(); 00157 00158 if (instance == nullptr) { 00159 instance = new HSelectionSetOOC(view, deep_select); 00160 return static_cast<HSelectionSetOOC *>(instance); 00161 } 00162 else { 00163 ASSERT(false); 00164 return nullptr; 00165 } 00166 } 00167 00170 static bool CanCreateInstance () 00171 { 00172 return Instance() == nullptr; 00173 } 00174 00177 virtual void Reset () 00178 { 00179 LockGuard lock(selection_mutex); 00180 00181 delete callback_key_infos; 00182 callback_key_infos = new VArray<CallbackKeyInfo>(); 00183 00184 filter.ClearWindows(); 00185 SelectionSet::Reset(); 00186 } 00187 00197 virtual bool DeleteSelection (bool emit_message = false) 00198 { 00199 using namespace ooc; 00200 using namespace ooc::delta; 00201 using namespace ooc::query; 00202 00203 HBaseView & view = *GetView(); 00204 00205 bool has_root; 00206 HC_Open_Segment_By_Key(view.GetModelKey());{ 00207 has_root = HC_QShow_Existence("root", "self") > 0; 00208 }HC_Close_Segment(); 00209 00210 if (!has_root) { 00211 return SelectionSet::DeleteSelection(); 00212 } 00213 00214 std::map<ooc::NodeHandle, std::vector<int>> handle_to_indices; 00215 { 00216 QueryIterator it = SelectedPoints(); 00217 while (true) { 00218 QueryIterator::Status status = it.GetStatus(); 00219 if (status != QueryIterator::Status_Alive) { 00220 if (status != QueryIterator::Status_Dead) { 00221 ASSERT(false); // replace with appropriate handling code 00222 return false; 00223 } 00224 break; 00225 } 00226 QueryResult const & res = *it; 00227 NodeHandle const & handle = res.GetNodeHandle(); 00228 int point_index = static_cast<int>(res.GetNodePointIndex()); 00229 handle_to_indices[handle].push_back(point_index); 00230 it.Advance(); 00231 } 00232 } 00233 00234 HC_KEY const ooc_root = HC_Create_Segment_Key_By_Key(view.GetModelKey(), "root"); 00235 Env env; 00236 if (!GetEnv(ooc_root, env)) { 00237 ASSERT(false); // replace with appropriate handling code 00238 return false; 00239 } 00240 SyncResult sync_res = ooc::delta::SynchronizeWith(env, [&](SyncToken const & sync_token) { 00241 using namespace ooc; 00242 using namespace ooc::delta; 00243 00244 auto const end = handle_to_indices.end(); 00245 auto it = handle_to_indices.begin(); 00246 for (; it != end; ++it) { 00247 auto & pair = *it; 00248 NodeHandle const & handle = pair.first; 00249 std::vector<int> & indices = pair.second; 00250 ModifyResult result = DeleteSpecificPoints(sync_token, handle, indices.data(), indices.size()); 00251 if (result != ModifyResult_Success) { 00252 ASSERT(false); // replace with appropriate handling code 00253 return; 00254 } 00255 } 00256 }); 00257 if (sync_res != SyncResult_Success) { 00258 ASSERT(false); // replace with appropriate handling code 00259 return false; 00260 } 00261 00262 Reset(); 00263 00264 if (emit_message) { 00265 m_pView->EmitDeleteSelectionListMessage(); 00266 } 00267 00268 return true; 00269 } 00270 00274 void SetDeepSelection (bool deep_select) 00275 { 00276 LockGuard lock(selection_mutex); 00277 Reset(); 00278 filter = HWindowFilterOOC(deep_select); 00279 } 00280 00283 ooc::query::QueryIterator SelectedPoints () 00284 { 00285 HBaseView & view = *GetView(); 00286 HC_KEY const ooc_root = HC_Create_Segment_Key_By_Key(view.GetModelKey(), "root"); 00287 ooc::Env env; 00288 if (!ooc::GetEnv(ooc_root, env)) { 00289 ASSERT(false); // replace with appropriate handling code 00290 return ooc::query::QueryIterator(); 00291 } 00292 return ooc::query::QueryPoints(env, filter); 00293 } 00294 00304 bool UpdateSelection () 00305 { 00306 if (callback_key_infos->Count() == 0) { 00307 return false; 00308 } 00309 00310 LockGuard lock(selection_mutex); 00311 00312 bool update_needed = false; 00313 00314 HBaseView & view = *GetView(); 00315 00316 HC_KEY key_path[] = { 00317 view.GetViewKey(), 00318 view.GetIncludeLinkKey(), 00319 }; 00320 00321 // Move data because the following code can modify original collection. 00322 VArray<CallbackKeyInfo> * infos = callback_key_infos; 00323 callback_key_infos = new VArray<CallbackKeyInfo>(); 00324 00325 size_t const count = infos->Count(); 00326 for (size_t i = 0; i < count; ++i) { 00327 CallbackKeyInfo const & info = infos->GetData(i); 00328 switch (info.type) { 00329 case CallbackType_Populate: { 00330 HC_KEY const segment_key = info.key; 00331 ooc::Point min_bounding; 00332 ooc::Point max_bounding; 00333 HC_Open_Segment_By_Key(segment_key);{ 00334 HC_Show_Bounding_Cuboid(&min_bounding, &max_bounding); 00335 if (!filter.RejectBounding(min_bounding, max_bounding)) { 00336 HC_Begin_Contents_Search(".", "shell");{ 00337 HC_KEY shell_key; 00338 while (HC_Find_Contents(nullptr, &shell_key)) { 00339 int point_count; 00340 HC_Show_Shell_Size(shell_key, &point_count, nullptr); 00341 ooc::Point const * points; 00342 HC_Show_Geometry_Pointer(shell_key, "points", &points); 00343 std::vector<int> points_to_highlight; 00344 for (int i = 0; i < point_count; ++i) { 00345 ooc::Point const & point = points[i]; 00346 if (filter.AcceptPoint(point, static_cast<size_t>(i))) { 00347 points_to_highlight.push_back(i); 00348 } 00349 } 00350 if (!points_to_highlight.empty()) { 00351 update_needed |= SelectSubentityOOC( 00352 shell_key, sizeof(key_path) / sizeof(HC_KEY), key_path, 00353 static_cast<int>(points_to_highlight.size()), 00354 nullptr, points_to_highlight.data(), nullptr, true); 00355 } 00356 } 00357 }HC_End_Contents_Search(); 00358 } 00359 }HC_Close_Segment(); 00360 } break; 00361 00362 case CallbackType_Deleted: { 00363 HC_KEY const shell_key = info.key; 00364 update_needed |= DeSelectOOC(shell_key, sizeof(key_path) / sizeof(HC_KEY), key_path); 00365 } break; 00366 00367 default: { 00368 ASSERT(false); 00369 } 00370 } 00371 } 00372 00373 delete infos; 00374 00375 return update_needed; 00376 } 00377 00383 void AddRectangleWindow (ooc::Point const & min, ooc::Point const & max) 00384 { 00385 LockGuard lock(selection_mutex); 00386 filter.AddRectangleWindow(*GetView(), min, max); 00387 } 00388 00395 void AddTriangleWindow (ooc::Point const & p1, ooc::Point const & p2, ooc::Point const & p3) 00396 { 00397 LockGuard lock(selection_mutex); 00398 filter.AddTriangleWindow(*GetView(), p1, p2, p3); 00399 } 00400 00405 template <typename Func> 00406 auto SynchronizeWith (Func const & task) -> decltype(task()) 00407 { 00408 LockGuard lock(selection_mutex); 00409 return task(); 00410 } 00411 00412 private: 00413 virtual bool Tick (float request_time, float actual_time) 00414 { 00415 UNREFERENCED(request_time); 00416 UNREFERENCED(actual_time); 00417 00418 while (UpdateSelection()) { 00419 GetView()->Update(); 00420 } 00421 00422 return true; 00423 } 00424 00425 void OnPopulateKey (HC_KEY segment_key) 00426 { 00427 if (filter.HasWindows()) { 00428 LockGuard lock(selection_mutex); 00429 if (filter.HasWindows()) { 00430 CallbackKeyInfo info(segment_key, CallbackType_Populate); 00431 callback_key_infos->Append(info); 00432 } 00433 } 00434 } 00435 00436 static void HC_CDECL StaticOnPopulateKey (HC_KEY segment_key) 00437 { 00438 static_cast<HSelectionSetOOC *>(Instance())->OnPopulateKey(segment_key); 00439 } 00440 00441 void OnDeletedKey (HC_KEY key, int type) 00442 { 00443 if (type == HIC_Geometry_Type_SHELL) { 00444 if (filter.HasWindows()) { 00445 LockGuard lock(selection_mutex); 00446 if (filter.HasWindows()) { 00447 CallbackKeyInfo info(key, CallbackType_Deleted); 00448 callback_key_infos->Append(info); 00449 } 00450 } 00451 } 00452 } 00453 00454 static void HC_CDECL StaticOnDeletedKey (HC_KEY key, int type) 00455 { 00456 static_cast<HSelectionSetOOC *>(Instance())->OnDeletedKey(key, type); 00457 } 00458 00459 private: 00460 HWindowFilterOOC filter; 00461 HMutexOOC selection_mutex; 00462 VArray<CallbackKeyInfo> * callback_key_infos; // Using a pointer for fast "move" semantics 00463 }; 00464 00465 00466 00467 00468