/* // // Copyright (c) 1993-2014 Robert McNeel & Associates. All rights reserved. // OpenNURBS, Rhinoceros, and Rhino3D are registered trademarks of Robert // McNeel & Associates. // // THIS SOFTWARE IS PROVIDED "AS IS" WITHOUT EXPRESS OR IMPLIED WARRANTY. // ALL IMPLIED WARRANTIES OF FITNESS FOR ANY PARTICULAR PURPOSE AND OF // MERCHANTABILITY ARE HEREBY DISCLAIMED. // // For complete openNURBS copyright information see . // //////////////////////////////////////////////////////////////// */ #include "opennurbs.h" #if !defined(ON_COMPILING_OPENNURBS) // This check is included in all opennurbs source .c and .cpp files to insure // ON_COMPILING_OPENNURBS is defined when opennurbs source is compiled. // When opennurbs source is being compiled, ON_COMPILING_OPENNURBS is defined // and the opennurbs .h files alter what is declared and how it is declared. #error ON_COMPILING_OPENNURBS must be defined when compiling opennurbs #endif ////////////////////////////////////////////////////////////////////////// // // ON_ComponentStatus bits // #define SELECTED_BIT (0x01U) #define SELECTED_PERSISTENT_BIT (0x02U) #define SELECTED_MASK (SELECTED_BIT | SELECTED_PERSISTENT_BIT) #define HIGHLIGHTED_BIT (0x04U) #define LOCKED_BIT (0x08U) #define HIDDEN_BIT (0x10U) // A mark is a tool used in a wide variety of ways by calculations. // Its value is unpredictable outside the scope of a specific code block. // High quality calculations will save and restore mark state, // but this is not always the case. // This state is not saved in archives. #define RUNTIME_MARK_BIT (0x20U) #define DELETED_BIT (0x40U) #define DAMAGED_BIT (0x80U) // Do NOT include RUNTIME_MARK_BIT in ALL_MASK #define ALL_MASK (SELECTED_MASK|HIGHLIGHTED_BIT|LOCKED_BIT|HIDDEN_BIT|DELETED_BIT|DAMAGED_BIT) ON_ComponentState ON_ComponentStateFromUnsigned( unsigned int state_as_unsigned ) { switch (state_as_unsigned) { ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Unset); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Clear); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::NotSelected); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Selected); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::SelectedPersistent); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::NotHighlighted); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Highlighted); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::NotHidden); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Hidden); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::NotLocked); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Locked); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::NotDamaged); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Damaged); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::NotDeleted); ON_ENUM_FROM_UNSIGNED_CASE(ON_ComponentState::Deleted); } return ON_ComponentState::Unset; } //enum STATE_FILTER : unsigned int //{ // selected = 0, // highlighted = 1, // hidden = 2, // locked = 4, // damaged = 8 //}; ON_ComponentStatus::ON_ComponentStatus( ON_ComponentState state ) { switch ( state) { case ON_ComponentState::Selected: m_status_flags = SELECTED_BIT; break; case ON_ComponentState::SelectedPersistent: m_status_flags = SELECTED_BIT | SELECTED_PERSISTENT_BIT; break; case ON_ComponentState::Highlighted: m_status_flags = HIGHLIGHTED_BIT; break; case ON_ComponentState::Hidden: m_status_flags = HIDDEN_BIT; break; case ON_ComponentState::Locked: m_status_flags = LOCKED_BIT; break; case ON_ComponentState::RuntimeMarkSet: m_status_flags = RUNTIME_MARK_BIT; break; case ON_ComponentState::Deleted: m_status_flags = DELETED_BIT; break; case ON_ComponentState::Damaged: m_status_flags = DAMAGED_BIT; break; default: m_status_flags = 0U; break; } } bool ON_ComponentStatus::operator==(ON_ComponentStatus b) { return (m_status_flags&ALL_MASK) == (b.m_status_flags&ALL_MASK); } bool ON_ComponentStatus::operator!=(ON_ComponentStatus b) { return (m_status_flags&ALL_MASK) != (b.m_status_flags&ALL_MASK); } const ON_ComponentStatus ON_ComponentStatus::LogicalAnd(ON_ComponentStatus lhs, ON_ComponentStatus rhs) { ON_ComponentStatus x; x.m_status_flags = (lhs.m_status_flags & rhs.m_status_flags); return x; } const ON_ComponentStatus ON_ComponentStatus::LogicalOr(ON_ComponentStatus lhs, ON_ComponentStatus rhs) { ON_ComponentStatus x; x.m_status_flags = (lhs.m_status_flags | rhs.m_status_flags); return x; } bool ON_ComponentStatus::StatusCheck( ON_ComponentStatus candidate, ON_ComponentStatus status_pass, ON_ComponentStatus status_fail ) { if (0 != ON_ComponentStatus::LogicalAnd(candidate, status_pass).m_status_flags) return true; if (0 != ON_ComponentStatus::LogicalAnd(candidate, status_fail).m_status_flags) return false; if (0 == status_fail.m_status_flags) return true; if (0 != status_pass.m_status_flags) return false; return true; } bool ON_ComponentStatus::IsClear() const { return (0 == (m_status_flags&ALL_MASK)); } bool ON_ComponentStatus::IsNotClear() const { return (0 != (m_status_flags&ALL_MASK)); } unsigned int ON_ComponentStatus::SetStatus( ON_ComponentStatus status_to_copy ) { unsigned char s1 = (status_to_copy.m_status_flags&ALL_MASK); if ( 0 == (SELECTED_BIT & s1) ) s1 &= ~SELECTED_PERSISTENT_BIT; if (s1 != (m_status_flags&ALL_MASK)) { const unsigned char mark = (m_status_flags&RUNTIME_MARK_BIT); m_status_flags = (s1|mark); return 1; } return 0; } unsigned int ON_ComponentStatus::SetStates( ON_ComponentStatus states_to_set ) { unsigned char s1 = (m_status_flags&ALL_MASK); unsigned char mask = (ALL_MASK & states_to_set.m_status_flags); if (0 == (SELECTED_BIT & mask)) { // no changes to s1's selected status mask &= ~SELECTED_PERSISTENT_BIT; } else { // states_to_set specifies setting selected or selected_persistent. // // Clear the persistent bit on s1. // If s1's SELECTED_PERSISTENT_BIT it is supposed to remain set, // then mask's SELECTED_PERSISTENT_BIT is set and the // s1 bit will get set by the s1 |= mask line below. s1 &= ~SELECTED_PERSISTENT_BIT; } s1 |= mask; if (s1 != (m_status_flags&ALL_MASK)) { const unsigned char mark = (m_status_flags&RUNTIME_MARK_BIT); m_status_flags = (s1|mark); return 1; } return 0; } unsigned int ON_ComponentStatus::ClearStates( ON_ComponentStatus states_to_clear ) { unsigned char s1 = (m_status_flags&ALL_MASK); unsigned char mask = ~(ALL_MASK & states_to_clear.m_status_flags); switch (SELECTED_MASK & mask) { case 0: // states_to_clear.IsSelectedPersistent() is true. // This means all selection states must be cleared from s1. // We are in this case because 0 = (SELECTED_MASK & mask) // so the s1 &= mask line below will remove any set selection // states from s1. break; case SELECTED_PERSISTENT_BIT: // states_to_clear.IsSelected() is true. // states_to_clear.IsSelectedPersistent() is false. // That is SELECTED_BIT = (SELECTED_MASK & states_to_clear.m_status_flags) // If s1 is selected persistent, it must stay selected. // If s1 is selected but not persistent, its selection state must be cleared. if (SELECTED_MASK == (SELECTED_MASK & s1)) { // s1 is selected persistent and must stay that way mask |= SELECTED_MASK; } else { // s1 is not selected persistent and must end up not selected. mask &= ~SELECTED_MASK; } break; default: // states_to_clear.IsSelected() is false. // No changes to s1's selection state. mask |= SELECTED_MASK; } s1 &= mask; if (s1 != (m_status_flags & ALL_MASK)) { // If input was selected and highlighted, // and output is not selected, // and hightlight and not explictily cleared, // then preserve highlight sync by auto-clearing highlight. if ( 0 == (SELECTED_MASK & s1) && 0 != (SELECTED_MASK & m_status_flags) && 0 != (HIGHLIGHTED_BIT & m_status_flags) && 0 != (HIGHLIGHTED_BIT & s1) ) { // Input was selected and hightlighted, // output is not selected. // Clear highlight automatically. s1 &= ~HIGHLIGHTED_BIT; } const unsigned char mark = (m_status_flags&RUNTIME_MARK_BIT); m_status_flags = (s1|mark); return 1; } return 0; } ON_ComponentState ON_ComponentStatus::SelectedState() const { switch ((m_status_flags & SELECTED_MASK)) { case 0U: return ON_ComponentState::NotSelected; case SELECTED_BIT: return ON_ComponentState::Selected; case (SELECTED_BIT|SELECTED_PERSISTENT_BIT): return ON_ComponentState::SelectedPersistent; } // error return ON_ComponentState::NotSelected; } unsigned int ON_ComponentStatus::SetSelectedState( bool bSelectedState, bool bPersistent, bool bSynchronizeHighlight ) { if (bSelectedState) { return bPersistent ? SetSelectedState(ON_ComponentState::SelectedPersistent, bSynchronizeHighlight) : SetSelectedState(ON_ComponentState::Selected, bSynchronizeHighlight) ; } return SetSelectedState(ON_ComponentState::NotSelected, bSynchronizeHighlight); } unsigned int ON_ComponentStatus::SetSelectedState( ON_ComponentState selected_state, bool bSynchronizeHighlight ) { bool bChanged = false; switch (selected_state) { case ON_ComponentState::NotSelected: if ( 0 != ClearStates(ON_ComponentStatus::Selected) ) bChanged = true; if ( bSynchronizeHighlight && 0 != ClearStates(ON_ComponentStatus::Highlighted) ) bChanged = true; break; case ON_ComponentState::Selected: if ( 0 != SetStates(ON_ComponentStatus::Selected) ) bChanged = true; if ( bSynchronizeHighlight && 0 != SetStates(ON_ComponentStatus::Highlighted) ) bChanged = true; break; case ON_ComponentState::SelectedPersistent: if ( 0 != SetStates(ON_ComponentStatus::SelectedPersistent) ) bChanged = true; if ( bSynchronizeHighlight && 0 != SetStates(ON_ComponentStatus::Highlighted) ) bChanged = true; break; } return bChanged ? 1U : 0U; } bool ON_ComponentStatus::IsSelected() const { return 0 != (m_status_flags & SELECTED_BIT); } bool ON_ComponentStatus::IsSelectedPersistent() const { return ( (SELECTED_BIT | SELECTED_PERSISTENT_BIT) == (m_status_flags & SELECTED_MASK) ); } unsigned int ON_ComponentStatus::SetHighlightedState( bool bIsHighlighted ) { return bIsHighlighted ? SetStates(ON_ComponentStatus::Highlighted) : ClearStates(ON_ComponentStatus::Highlighted); } bool ON_ComponentStatus::IsHighlighted() const { return 0 != (m_status_flags & HIGHLIGHTED_BIT); } bool ON_ComponentStatus::RuntimeMark() const { return ( 0 != (m_status_flags & RUNTIME_MARK_BIT) ); } unsigned int ON_ComponentStatus::SetRuntimeMark( bool bRuntimeMark ) { return bRuntimeMark ? SetRuntimeMark() : ClearRuntimeMark(); } unsigned int ON_ComponentStatus::SetRuntimeMark() { const unsigned char c = (m_status_flags | RUNTIME_MARK_BIT); if (c != m_status_flags) { m_status_flags = c; return 1; } return 0; } unsigned int ON_ComponentStatus::ClearRuntimeMark() { const unsigned char c = (m_status_flags & ~RUNTIME_MARK_BIT); if (c != m_status_flags) { m_status_flags = c; return 1; } return 0; } unsigned int ON_ComponentStatus::SetHiddenState( bool bIsHidden ) { return bIsHidden ? SetStates(ON_ComponentStatus::Hidden) : ClearStates(ON_ComponentStatus::Hidden); } bool ON_ComponentStatus::IsHidden() const { return 0 != (m_status_flags & HIDDEN_BIT); } unsigned int ON_ComponentStatus::SetLockedState( bool bIsLocked ) { return bIsLocked ? SetStates(ON_ComponentStatus::Locked) : ClearStates(ON_ComponentStatus::Locked); } bool ON_ComponentStatus::IsLocked() const { return 0 != (m_status_flags & LOCKED_BIT); } unsigned int ON_ComponentStatus::SetDeletedState( bool bIsDeleted ) { return bIsDeleted ? SetStates(ON_ComponentStatus::Deleted) : ClearStates(ON_ComponentStatus::Deleted); } bool ON_ComponentStatus::IsDeleted() const { return 0 != (m_status_flags & DELETED_BIT); } unsigned int ON_ComponentStatus::SetDamagedState( bool bIsDamaged ) { return bIsDamaged ? SetStates(ON_ComponentStatus::Damaged) : ClearStates(ON_ComponentStatus::Damaged); } bool ON_ComponentStatus::IsDamaged() const { return 0 != (m_status_flags & DAMAGED_BIT); } bool ON_ComponentStatus::operator==(const ON_ComponentStatus& other) const { return m_status_flags == other.m_status_flags; } bool ON_ComponentStatus::operator!=(const ON_ComponentStatus& other) const { return m_status_flags != other.m_status_flags; } bool ON_ComponentStatus::AllEqualStates( ON_ComponentStatus states_filter, ON_ComponentStatus comparand ) const { unsigned char mask = (states_filter.m_status_flags & ALL_MASK); mask &= ~SELECTED_PERSISTENT_BIT; if (0 == mask) return false; unsigned char s1 = mask & m_status_flags; unsigned char s2 = mask & comparand.m_status_flags; return (s1 == s2); } bool ON_ComponentStatus::SomeEqualStates( ON_ComponentStatus states_filter, ON_ComponentStatus comparand ) const { unsigned char mask = (states_filter.m_status_flags & ALL_MASK); mask &= ~SELECTED_PERSISTENT_BIT; if (0 == mask) return false; unsigned char s1 = mask & m_status_flags; unsigned char s2 = mask & comparand.m_status_flags; if (0 != (s1&s2)) return true; // some set states are equal s1 = mask & ~s1; s2 = mask & ~s2; if (0 != (s1&s2)) return true; // some clear states are equal return false; } bool ON_ComponentStatus::NoEqualStates( ON_ComponentStatus states_filter, ON_ComponentStatus comparand ) const { unsigned char mask = (states_filter.m_status_flags & ALL_MASK); mask &= ~SELECTED_PERSISTENT_BIT; if (0 == mask) return false; unsigned char s1 = mask & m_status_flags; unsigned char s2 = mask & comparand.m_status_flags; return (mask == (s1 ^ s2)); } bool ON_AggregateComponentStatus::ClearAllStates() { if (m_current <= 1) { unsigned char c = m_current; unsigned int n = m_component_count; *this = ON_AggregateComponentStatus::Empty; m_current = c; n = m_component_count; return true; } return false; } bool ON_AggregateComponentStatus::ClearAggregateStatus( ON_ComponentStatus states_to_clear ) { if (states_to_clear.m_status_flags == ON_ComponentStatus::AllSet.m_status_flags || 0 == m_component_count) return ClearAllStates(); if (1 == m_current) { m_aggregate_status.ClearStates(states_to_clear); const unsigned char s1 = m_aggregate_status.m_status_flags; if (0 == (SELECTED_BIT & s1)) { m_selected_count = 0; m_selected_persistent_count = 0; } else if (0 == (SELECTED_PERSISTENT_BIT & s1)) { m_selected_count -= m_selected_persistent_count; m_selected_persistent_count = 0; } if (0 == (HIGHLIGHTED_BIT & s1)) m_highlighted_count = 0; if (0 == (LOCKED_BIT & s1)) m_locked_count = 0; if (0 == (HIDDEN_BIT & s1)) m_hidden_count = 0; if (0 == (DAMAGED_BIT & s1)) m_damaged_count = 0; return true; } return false; } bool ON_AggregateComponentStatus::IsEmpty() const { return (0 == m_current); } bool ON_AggregateComponentStatus::IsCurrent() const { return (1 == m_current); } void ON_AggregateComponentStatus::MarkAsNotCurrent() { if (2 != m_current) { *this = ON_AggregateComponentStatus::Empty; m_current = 2; } } ON_ComponentStatus ON_AggregateComponentStatus::AggregateStatus() const { return m_aggregate_status; } unsigned int ON_AggregateComponentStatus::ComponentCount() const { return m_component_count; } unsigned int ON_AggregateComponentStatus::SelectedCount() const { return m_selected_count; } unsigned int ON_AggregateComponentStatus::SelectedPersistentCount() const { return m_selected_persistent_count; } unsigned int ON_AggregateComponentStatus::HighlightedCount() const { return m_highlighted_count; } unsigned int ON_AggregateComponentStatus::HiddenCount() const { return m_hidden_count; } unsigned int ON_AggregateComponentStatus::LockedCount() const { return m_locked_count; } unsigned int ON_AggregateComponentStatus::DamagedCount() const { return m_locked_count; } bool ON_AggregateComponentStatus::Add( const ON_AggregateComponentStatus& aggregate_status ) { if (0 == m_current ) { *this = aggregate_status; return m_current <= 1; } if ( m_current >= 2 ) return false; if ( 0 == aggregate_status.m_current ) return true; if ( aggregate_status.m_current >= 2 ) { MarkAsNotCurrent(); return false; } m_component_count += aggregate_status.m_component_count; const unsigned char s1 = aggregate_status.m_aggregate_status.m_status_flags; if ( 0 == s1 ) return true; if (0 != (SELECTED_BIT & s1)) { m_selected_count += aggregate_status.m_selected_count; m_selected_persistent_count += aggregate_status.m_selected_persistent_count; } if ( 0 != (HIGHLIGHTED_BIT & s1) ) m_highlighted_count += aggregate_status.m_highlighted_count; if ( 0 != (LOCKED_BIT & s1) ) m_locked_count += aggregate_status.m_locked_count; if ( 0 != (HIDDEN_BIT & s1) ) m_hidden_count += aggregate_status.m_hidden_count; if ( 0 != (DAMAGED_BIT & s1) ) m_damaged_count += aggregate_status.m_damaged_count; m_aggregate_status.m_status_flags |= s1; return true; } bool ON_AggregateComponentStatus::Add( ON_ComponentStatus component_status ) { if ( 0 == m_current ) m_current = 1; else if ( 1 != m_current ) return false; m_component_count++; const unsigned char s1 = component_status.m_status_flags; if ( 0 == s1 ) return true; if (0 != (SELECTED_BIT & s1)) { m_selected_count++; if (0 != (SELECTED_PERSISTENT_BIT & s1)) m_selected_persistent_count++; } if ( 0 != (HIGHLIGHTED_BIT & s1) ) m_highlighted_count++; if ( 0 != (LOCKED_BIT & s1) ) m_locked_count++; if ( 0 != (HIDDEN_BIT & s1) ) m_hidden_count++; if ( 0 != (DAMAGED_BIT & s1) ) m_damaged_count++; m_aggregate_status.m_status_flags |= s1; return true; } ///////////////////////////////////////////////////////////////// // // ON_Object component status virtual interface // // unsigned int ON_Object::ClearAllComponentStates() const { return ClearComponentStates(ON_ComponentStatus::AllSet); } // virtual unsigned int ON_Object::ClearComponentStates( ON_ComponentStatus states_to_clear ) const { return 0U; } //virtual unsigned int ON_Object::GetComponentsWithSetStates( ON_ComponentStatus states_filter, bool bAllEqualStates, ON_SimpleArray< ON_COMPONENT_INDEX >& components ) const { components.SetCount(0); return 0U; } // virtual unsigned int ON_Object::SetComponentStates( ON_COMPONENT_INDEX component_index, ON_ComponentStatus states_to_set ) const { return 0U; } // virtual unsigned int ON_Object::ClearComponentStates( ON_COMPONENT_INDEX component_index, ON_ComponentStatus states_to_clear ) const { return 0U; } // virtual unsigned int ON_Object::SetComponentStatus( ON_COMPONENT_INDEX component_index, ON_ComponentStatus status_to_copy ) const { return 0U; } // virtual ON_AggregateComponentStatus ON_Object::AggregateComponentStatus() const { return ON_AggregateComponentStatus::Empty; } // virtual void ON_Object::MarkAggregateComponentStatusAsNotCurrent() const { return; } // virtual bool ON_Object::DeleteComponents( const ON_COMPONENT_INDEX* ci_list, size_t ci_count ) { return false; }