Alphabetical Class Index  Class Hierarchy   File Members   Compound Members   File List  

HSelectionSetOOC.h
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