/* $NoKeywords: $ */ /* // // Copyright (c) 1993-2012 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 // obsolete V2 and V5 annotation objects #include "opennurbs_internal_V2_annotation.h" #include "opennurbs_internal_V5_annotation.h" // This define is up here so anybody who want's to defeat the // bozo vaccine has to be doing it on purpose. #define BOZO_VACCINE_699FCC4262D4488c9109F1B7A37CE926 // Added for v5 - 12-10-2009 LW ON_OBJECT_IMPLEMENT(ON_OBSOLETE_V5_TextExtra,ON_UserData,"D90490A5-DB86-49f8-BDA1-9080B1F4E976"); ON_OBSOLETE_V5_TextExtra::ON_OBSOLETE_V5_TextExtra() { m_userdata_uuid = ON_CLASS_ID(ON_OBSOLETE_V5_TextExtra); m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata // The id must be the version 5 id because // V6 SaveAs V5 needs to work, but SaveAs // V4 should not write this userdata. m_userdata_copycount = 1; SetDefaults(); } ON_OBSOLETE_V5_TextExtra::~ON_OBSOLETE_V5_TextExtra() { } ON_OBSOLETE_V5_TextExtra* ON_OBSOLETE_V5_TextExtra::TextExtension(ON_OBSOLETE_V5_TextObject* pText, bool bCreate) { ON_OBSOLETE_V5_TextExtra* pExtra = 0; if(pText) { pExtra = ON_OBSOLETE_V5_TextExtra::Cast(pText->GetUserData(ON_CLASS_ID(ON_OBSOLETE_V5_TextExtra))); if(pExtra == 0 && bCreate) { pExtra = new ON_OBSOLETE_V5_TextExtra; if(pExtra) { if(!pText->AttachUserData(pExtra)) { delete pExtra; pExtra = 0; } } } } return pExtra; } const ON_OBSOLETE_V5_TextExtra* ON_OBSOLETE_V5_TextExtra::TextExtension(const ON_OBSOLETE_V5_TextObject* pText, bool bCreate) { return TextExtension((ON_OBSOLETE_V5_TextObject*)pText, bCreate); } void ON_OBSOLETE_V5_TextExtra::SetDefaults() { m_parent_uuid = ON_nil_uuid; m_color_source = 0; m_mask_color = 0; m_border_offset = 0.1; } void ON_OBSOLETE_V5_TextExtra::Dump( ON_TextLog& text_log ) const { // do nothing } unsigned int ON_OBSOLETE_V5_TextExtra::SizeOf() const { unsigned int sz = ON_UserData::SizeOf(); sz += sizeof(*this) - sizeof(ON_UserData); return sz; } bool ON_OBSOLETE_V5_TextExtra::Write(ON_BinaryArchive& archive) const { bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if(rc) rc = archive.WriteUuid(m_parent_uuid); if(rc) rc = archive.WriteBool(m_bDrawMask); if(rc) rc = archive.WriteInt(m_color_source); if(rc) rc = archive.WriteColor(m_mask_color); if(rc) rc = archive.WriteDouble(m_border_offset); if(!archive.EndWrite3dmChunk()) rc = false; return rc; } bool ON_OBSOLETE_V5_TextExtra::Read(ON_BinaryArchive& archive) { int major_version = 1; int minor_version = 0; bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if(!rc) return false; if(major_version != 1) return false; if(rc) rc = archive.ReadUuid(m_parent_uuid); if(rc) rc = archive.ReadBool(&m_bDrawMask); if(rc) rc = archive.ReadInt(&m_color_source); if(rc) rc = archive.ReadColor(m_mask_color); if(rc) rc = archive.ReadDouble(&m_border_offset); if ( !archive.EndRead3dmChunk() ) rc = false; return rc; } bool ON_OBSOLETE_V5_TextExtra::GetDescription( ON_wString& description) { description = L"Userdata extension of ON_OBSOLETE_V2_TextObject"; return true; } bool ON_OBSOLETE_V5_TextExtra::Archive() const { // true to write to file return true; } ON_UUID ON_OBSOLETE_V5_TextExtra::ParentUUID() const { return m_parent_uuid; } void ON_OBSOLETE_V5_TextExtra::SetParentUUID( ON_UUID parent_uuid) { m_parent_uuid = parent_uuid; } bool ON_OBSOLETE_V5_TextExtra::DrawTextMask() const { return m_bDrawMask; } void ON_OBSOLETE_V5_TextExtra::SetDrawTextMask(bool bDraw) { m_bDrawMask = bDraw; } int ON_OBSOLETE_V5_TextExtra::MaskColorSource() const { return m_color_source; } void ON_OBSOLETE_V5_TextExtra::SetMaskColorSource(int source) { if(source == 1) m_color_source = 1; else m_color_source = 0; } ON_Color ON_OBSOLETE_V5_TextExtra::MaskColor() const { return m_mask_color; } void ON_OBSOLETE_V5_TextExtra::SetMaskColor(ON_Color color) { m_mask_color = color; } double ON_OBSOLETE_V5_TextExtra::MaskOffsetFactor() const { return m_border_offset; } void ON_OBSOLETE_V5_TextExtra::SetMaskOffsetFactor(double offset) { m_border_offset = offset; } //-------------------- // Added for v5 - 4-20-07 LW ON_OBJECT_IMPLEMENT(ON_OBSOLETE_V5_DimExtra,ON_UserData,"8AD5B9FC-0D5C-47fb-ADFD-74C28B6F661E"); ON_OBSOLETE_V5_DimExtra::ON_OBSOLETE_V5_DimExtra() { m_userdata_uuid = ON_CLASS_ID(ON_OBSOLETE_V5_DimExtra); m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata // The id must be the version 5 id because // V6 SaveAs V5 needs to work, but SaveAs // V4 should not write this userdata. m_userdata_copycount = 1; SetDefaults(); } ON_OBSOLETE_V5_DimExtra::~ON_OBSOLETE_V5_DimExtra() { } static ON_OBSOLETE_V5_DimExtra* AnnotationExtension(ON_OBSOLETE_V5_Annotation* pDim, bool bCreate) { ON_OBSOLETE_V5_DimExtra* pExtra = 0; if(pDim) { pExtra = ON_OBSOLETE_V5_DimExtra::Cast(pDim->GetUserData(ON_CLASS_ID(ON_OBSOLETE_V5_DimExtra))); if(pExtra == 0 && bCreate) { pExtra = new ON_OBSOLETE_V5_DimExtra; if( pExtra) { if(!pDim->AttachUserData(pExtra)) { delete pExtra; pExtra = 0; } } } } return pExtra; } ON_OBSOLETE_V5_DimExtra* ON_OBSOLETE_V5_DimExtra::DimensionExtension(ON_OBSOLETE_V5_DimLinear* pDim, bool bCreate) { return AnnotationExtension((ON_OBSOLETE_V5_Annotation*)pDim, bCreate); } const ON_OBSOLETE_V5_DimExtra* ON_OBSOLETE_V5_DimExtra::DimensionExtension(const ON_OBSOLETE_V5_DimLinear* pDim, bool bCreate) { return DimensionExtension((ON_OBSOLETE_V5_DimLinear*)pDim, bCreate); } ON_OBSOLETE_V5_DimExtra* ON_OBSOLETE_V5_DimExtra::DimensionExtension(ON_OBSOLETE_V5_DimRadial* pDim, bool bCreate) { return AnnotationExtension((ON_OBSOLETE_V5_Annotation*)pDim, bCreate); } const ON_OBSOLETE_V5_DimExtra* ON_OBSOLETE_V5_DimExtra::DimensionExtension(const ON_OBSOLETE_V5_DimRadial* pDim, bool bCreate) { return DimensionExtension((ON_OBSOLETE_V5_DimRadial*)pDim, bCreate); } ON_OBSOLETE_V5_DimExtra* ON_OBSOLETE_V5_DimExtra::DimensionExtension(ON_OBSOLETE_V5_DimOrdinate* pDim, bool bCreate) { return AnnotationExtension((ON_OBSOLETE_V5_Annotation*)pDim, bCreate); } const ON_OBSOLETE_V5_DimExtra* ON_OBSOLETE_V5_DimExtra::DimensionExtension(const ON_OBSOLETE_V5_DimOrdinate* pDim, bool bCreate) { return DimensionExtension((ON_OBSOLETE_V5_DimOrdinate*)pDim, bCreate); } void ON_OBSOLETE_V5_DimExtra::SetDefaults() { m_partent_uuid = ON_nil_uuid; m_arrow_position = 0; m_text_rects = 0; m_distance_scale = 1.0; m_modelspace_basepoint = ON_3dPoint::Origin; m_detail_measured = ON_nil_uuid; } void ON_OBSOLETE_V5_DimExtra::Dump( ON_TextLog& text_log ) const { // do nothing } unsigned int ON_OBSOLETE_V5_DimExtra::SizeOf() const { unsigned int sz = ON_UserData::SizeOf(); sz += sizeof(*this) - sizeof(ON_UserData); return sz; } bool ON_OBSOLETE_V5_DimExtra::Write(ON_BinaryArchive& archive) const { int major_version = 1; int minor_version = 2; bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,major_version,minor_version); if(rc) rc = archive.WriteUuid( m_partent_uuid); if(rc) rc = archive.WriteInt( m_arrow_position); if(rc) { if( m_text_rects) { rc = archive.WriteInt( 7); rc = archive.WriteInt( 28, (const int*)m_text_rects); } else rc = archive.WriteInt( 0); } // 21 June 2010 Added distance scale, minor version 1 if(rc) rc = archive.WriteDouble(m_distance_scale); // 27 Aug, 2014 Added detail measured, minor version 2 if (rc) rc = archive.WriteUuid(m_detail_measured); if(!archive.EndWrite3dmChunk()) rc = false; return rc; } bool ON_OBSOLETE_V5_DimExtra::Read(ON_BinaryArchive& archive) { int major_version = 1; int minor_version = 0; bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if(!rc) return false; if(major_version < 1) return false; if(rc) rc = archive.ReadUuid(m_partent_uuid); if(rc) rc = archive.ReadInt(&m_arrow_position); int rect_count = 0; if(rc) rc = archive.ReadInt( &rect_count); if( rc && rect_count) rc = archive.ReadInt( rect_count, (int*)m_text_rects); // 21 June 2010 Added distance scale, minor version 1 if (minor_version > 0) { if (rc) rc = archive.ReadDouble(&m_distance_scale); } // 27 Aug, 2014 Added detail measured, minor version 2 if (minor_version > 1) { m_detail_measured = ON_nil_uuid; if (rc) rc = archive.ReadUuid(m_detail_measured); } if (!archive.EndRead3dmChunk()) rc = false; return rc; } bool ON_OBSOLETE_V5_DimExtra::GetDescription( ON_wString& description) { description = L"Userdata extension of ON_Dimensions"; return true; } bool ON_OBSOLETE_V5_DimExtra::Archive() const { // true to write to file return true; } ON_UUID ON_OBSOLETE_V5_DimExtra::ParentUUID() const { return m_partent_uuid; } void ON_OBSOLETE_V5_DimExtra::SetParentUUID( ON_UUID partent_uuid) { m_partent_uuid = partent_uuid; } int ON_OBSOLETE_V5_DimExtra::ArrowPosition() const { return m_arrow_position; } void ON_OBSOLETE_V5_DimExtra::SetArrowPosition( int position) { if( position > 0) m_arrow_position = 1; else if( position < 0) m_arrow_position = -1; else m_arrow_position = 0; } double ON_OBSOLETE_V5_DimExtra::DistanceScale() const { return m_distance_scale; } void ON_OBSOLETE_V5_DimExtra::SetDistanceScale(double s) { m_distance_scale = s; } void ON_OBSOLETE_V5_DimExtra::SetModelSpaceBasePoint(ON_3dPoint basepoint) { m_modelspace_basepoint = basepoint; } ON_3dPoint ON_OBSOLETE_V5_DimExtra::ModelSpaceBasePoint() const { return m_modelspace_basepoint; } ON_UUID ON_OBSOLETE_V5_DimExtra::DetailMeasured() const { return m_detail_measured; } void ON_OBSOLETE_V5_DimExtra::SetDetailMeasured(ON_UUID detail_id) { m_detail_measured = detail_id; } /* const wchar_t* ON_OBSOLETE_V5_DimExtra::ToleranceUpperString() const { return m_upper_string; } ON_wString& ON_OBSOLETE_V5_DimExtra::ToleranceUpperString() { return m_upper_string; } void ON_OBSOLETE_V5_DimExtra::SetToleranceUpperString( const wchar_t* upper_string) { m_upper_string = upper_string; } void ON_OBSOLETE_V5_DimExtra::SetToleranceUpperString( ON_wString& upper_string) { m_upper_string = upper_string; } const wchar_t* ON_OBSOLETE_V5_DimExtra::ToleranceLowerString() const { return m_lower_string; } ON_wString& ON_OBSOLETE_V5_DimExtra::ToleranceLowerString() { return m_lower_string; } void ON_OBSOLETE_V5_DimExtra::SetToleranceLowerString( const wchar_t* lower_string) { m_lower_string = lower_string; } void ON_OBSOLETE_V5_DimExtra::SetToleranceLowerString( ON_wString& lower_string) { m_lower_string = lower_string; } const wchar_t* ON_OBSOLETE_V5_DimExtra::AlternateString() const { return m_alt_string; } ON_wString& ON_OBSOLETE_V5_DimExtra::AlternateString() { return m_alt_string; } void ON_OBSOLETE_V5_DimExtra::SetAlternateString( const wchar_t* alt_string) { m_alt_string = alt_string; } void ON_OBSOLETE_V5_DimExtra::SetAlternateString( ON_wString& alt_string) { m_alt_string = alt_string; } const wchar_t* ON_OBSOLETE_V5_DimExtra::AlternateToleranceUpperString() const { return m_alt_upper_string; } ON_wString& ON_OBSOLETE_V5_DimExtra::AlternateToleranceUpperString() { return m_alt_upper_string; } void ON_OBSOLETE_V5_DimExtra::SetAlternateToleranceUpperString( const wchar_t* upper_string) { m_alt_upper_string = upper_string; } void ON_OBSOLETE_V5_DimExtra::SetAlternateToleranceUpperString( ON_wString& upper_string) { m_alt_upper_string = upper_string; } const wchar_t* ON_OBSOLETE_V5_DimExtra::AlternateToleranceLowerString() const { return m_alt_lower_string; } ON_wString& ON_OBSOLETE_V5_DimExtra::AlternateToleranceLowerString() { return m_alt_lower_string; } void ON_OBSOLETE_V5_DimExtra::SetAlternateToleranceLowerString( const wchar_t* lower_string) { m_alt_lower_string = lower_string; } void ON_OBSOLETE_V5_DimExtra::SetAlternateToleranceLowerString( ON_wString& lower_string) { m_alt_lower_string = lower_string; } */ //-------------------- ON_VIRTUAL_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_Annotation, ON_Geometry, "8D820224-BC6C-46b4-9066-BF39CC13AEFB"); ON_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_DimLinear, ON_OBSOLETE_V5_Annotation, "BD57F33B-A1B2-46e9-9C6E-AF09D30FFDDE"); ON_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_DimRadial, ON_OBSOLETE_V5_Annotation, "B2B683FC-7964-4e96-B1F9-9B356A76B08B"); ON_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_DimAngular, ON_OBSOLETE_V5_Annotation, "841BC40B-A971-4a8e-94E5-BBA26D67348E"); ON_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_TextObject, ON_OBSOLETE_V5_Annotation, "46F75541-F46B-48be-AA7E-B353BBE068A7"); ON_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_Leader, ON_OBSOLETE_V5_Annotation, "14922B7A-5B65-4f11-8345-D415A9637129"); ON_OBJECT_IMPLEMENT( ON_TextDot, ON_Geometry, "74198302-CDF4-4f95-9609-6D684F22AB37"); ON_OBJECT_IMPLEMENT( ON_OBSOLETE_V5_DimOrdinate,ON_OBSOLETE_V5_Annotation, "C8288D69-5BD8-4f50-9BAF-525A0086B0C3"); // class ON_OBSOLETE_V5_Annotation //-------------------------------------------------------------------- int ON_OBSOLETE_V5_Annotation::V5_3dmArchiveDimStyleIndex() const { return m_v5_3dm_archive_dimstyle_index; } void ON_OBSOLETE_V5_Annotation::SetV5_3dmArchiveDimStyleIndex( int V5_dim_style_index ) { m_v5_3dm_archive_dimstyle_index = V5_dim_style_index; } void ON_OBSOLETE_V5_Annotation::Create() { Destroy(); m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine; m_v5_3dm_archive_dimstyle_index = -1; m_textheight = 1.0; } void ON_OBSOLETE_V5_Annotation::Destroy() { m_v5_3dm_archive_dimstyle_index = -1; // 10-27-03 LW memory leak prevention m_points.Empty(); SetTextValue(0); SetTextFormula(0); m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtNothing; m_plane = ON_xy_plane; m_userpositionedtext = false; m_justification = 0; m_annotative_scale = true; } void ON_OBSOLETE_V5_Annotation::EmergencyDestroy() { m_points.EmergencyDestroy(); m_usertext.EmergencyDestroy(); } ON_OBSOLETE_V5_Annotation::ON_OBSOLETE_V5_Annotation() { Create(); } ON_OBSOLETE_V5_Annotation::~ON_OBSOLETE_V5_Annotation() { Destroy(); } ON_OBSOLETE_V5_Annotation* ON_OBSOLETE_V5_Annotation::CreateFromV2Annotation( const class ON_OBSOLETE_V2_Annotation& V2_annotation, const class ON_3dmAnnotationContext* annotation_context ) { for (;;) { const ON_OBSOLETE_V2_Leader* V2_leader = ON_OBSOLETE_V2_Leader::Cast(&V2_annotation); if (nullptr == V2_leader && ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader == V2_annotation.m_type) V2_leader = static_cast(&V2_annotation); if (nullptr == V2_leader) break; return ON_OBSOLETE_V5_Leader::CreateFromV2Leader( *V2_leader, annotation_context, nullptr ); } for(;;) { const ON_OBSOLETE_V2_TextObject* V2_text_object = ON_OBSOLETE_V2_TextObject::Cast(&V2_annotation); if (nullptr == V2_text_object) break; return ON_OBSOLETE_V5_TextObject::CreateFromV2TextObject( *V2_text_object, annotation_context, nullptr ); } for(;;) { const ON_OBSOLETE_V2_DimRadial* V2_radial_dimension = ON_OBSOLETE_V2_DimRadial::Cast(&V2_annotation); if (nullptr == V2_radial_dimension) break; return ON_OBSOLETE_V5_DimRadial::CreateFromV2RadialDimension( *V2_radial_dimension, annotation_context, nullptr ); } for(;;) { const ON_OBSOLETE_V2_DimLinear* V2_linear_dimension = ON_OBSOLETE_V2_DimLinear::Cast(&V2_annotation); if (nullptr == V2_linear_dimension) break; return ON_OBSOLETE_V5_DimLinear::CreateFromV2LinearDimension( *V2_linear_dimension, annotation_context, nullptr ); } for(;;) { const ON_OBSOLETE_V2_DimAngular* V2_angular_dimension = ON_OBSOLETE_V2_DimAngular::Cast(&V2_annotation); if (nullptr == V2_angular_dimension) break; return ON_OBSOLETE_V5_DimAngular::CreateFromV2AngularDimension( *V2_angular_dimension, annotation_context, nullptr ); } return nullptr; } ////void ON_OBSOLETE_V5_Annotation::Internal_SetDimStyleFromV6Annotation( //// const class ON_Annotation& V6_annotation, //// const class ON_3dmAnnotationContext* annotation_context ////) ////{ //// if (nullptr != annotation_context) //// SetV6_DimStyleId(annotation_context->DimStyleId(), annotation_context->V5_ArchiveDimStyleIndex()); //// else //// SetV6_DimStyleId(V6_annotation.DimensionStyleId(), ON_UNSET_INT_INDEX); ////} ON_OBSOLETE_V5_Annotation* ON_OBSOLETE_V5_Annotation::CreateFromV6Annotation( const class ON_Annotation& V6_annotation, const class ON_3dmAnnotationContext* annotation_context ) { const ON_Text* V6_text_object = ON_Text::Cast(&V6_annotation); if (nullptr != V6_text_object) return ON_OBSOLETE_V5_TextObject::CreateFromV6TextObject(*V6_text_object, annotation_context, nullptr); const ON_Leader* V6_leader = ON_Leader::Cast(&V6_annotation); if (nullptr != V6_leader) return ON_OBSOLETE_V5_Leader::CreateFromV6Leader(*V6_leader, annotation_context, nullptr); const ON_DimRadial* V6_dim_radial = ON_DimRadial::Cast(&V6_annotation); if (nullptr != V6_dim_radial) return ON_OBSOLETE_V5_DimRadial::CreateFromV6DimRadial(*V6_dim_radial, annotation_context, nullptr); const ON_DimLinear* V6_dim_linear = ON_DimLinear::Cast(&V6_annotation); if (nullptr != V6_dim_linear) return ON_OBSOLETE_V5_DimLinear::CreateFromV6DimLinear(*V6_dim_linear, annotation_context, nullptr); const ON_DimAngular* V6_dim_angle = ON_DimAngular::Cast(&V6_annotation); if (nullptr != V6_dim_angle) return ON_OBSOLETE_V5_DimAngular::CreateFromV6DimAngular(*V6_dim_angle, annotation_context, nullptr); const ON_DimOrdinate* V6_dim_ordinate = ON_DimOrdinate::Cast(&V6_annotation); if (nullptr != V6_dim_ordinate) return ON_OBSOLETE_V5_DimOrdinate::CreateFromV6DimOrdinate(*V6_dim_ordinate, annotation_context, nullptr); return nullptr; } bool ON_OBSOLETE_V5_Annotation::EvaluatePoint( const ON_ObjRef& objref, ON_3dPoint& P) const { bool rc = false; switch( objref.m_component_index.m_type ) { case ON_COMPONENT_INDEX::dim_linear_point: case ON_COMPONENT_INDEX::dim_radial_point: case ON_COMPONENT_INDEX::dim_angular_point: case ON_COMPONENT_INDEX::dim_ordinate_point: case ON_COMPONENT_INDEX::dim_text_point: { ON_2dPoint uv = Point(objref.m_component_index.m_index); if ( uv.IsValid() ) { P = m_plane.PointAt(uv.x,uv.y); rc = true; } } break; default: // other enum values skipped on purpose break; } if (!rc) { P = ON_3dPoint::UnsetPoint; } return rc; } bool ON_OBSOLETE_V5_Annotation::IsValid( ON_TextLog* text_log ) const { if ( !m_plane.IsValid() ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_Annotation - m_plane is not valid\n"); } return false; } const int points_count = m_points.Count(); int i; for ( i = 0; i < points_count; i++ ) { if ( !m_points[i].IsValid() ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_Annotation - m_points[%d] is not valid.\n"); } return false; } } switch ( m_type ) { case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate: break; default: if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_Annotation - m_type = %d is not a valid enum value\n",m_type); } return false; break; } return true; } static bool WriteAnnotation2UserText_V4( ON_BinaryArchive& file, const ON_wString& s ) { bool rc; ON_wString s4; int len = s.Length(); for(int i = 0; i < len; i++) { if(s[i] == '\r' || s[i] == '\n') { s4 += L'\r'; s4 += L'\n'; // May 24, 2012 Tim - Fix for RR 100260. If we use a while here we // miss adding carriage returns where the user really meant to have a // blank line. If we only check the next character and then continue on // we preserve the blank lines. if(i < len-1 && (s[i+1] == L'\r' || s[i+1] == L'\n')) i++; continue; } s4 += s[i]; } rc = file.WriteString(s4); return rc; } static bool WriteAnnotation2UserText_V5( ON_BinaryArchive& file, const ON_wString& s ) { bool rc; rc = file.WriteString( s); return rc; } bool ON_OBSOLETE_V5_Annotation::Write( ON_BinaryArchive& file ) const { //int i; unsigned int ui; bool rc = false; bool bInChunk = (file.Archive3dmVersion() >= 5 ); if ( bInChunk ) { // 18 October 2007 Dale Lear // I modified this code so that V5 files can add // information in ON_OBSOLETE_V5_Annotation chunks without // breaking past and future file IO. // The opennurbs version number before this change was // 20071017*. I changed the version to 20071018* when // I checked in this IO change. The reason I can get // away with this is that nobody except developers has // a copy of V5 Rhino. // 28 Aug, 2010 - Lowell - changed minor version 0->1 to write // annotative scale flag // 24 September 2010 Dale Lear // I incremented chunk version to 1.2 and wrote the TextFormaula() string. rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,3); if (!rc) return false; } else { // For archives with opennurbs version < 200710180 // The code before version 200710180 does not properly // handle new additions to the ON_OBSOLETE_V5_Annotation chunk. rc = file.Write3dmChunkVersion( 1, 0 ); } while(rc) { ui = static_cast(m_type); rc = file.WriteInt(ui); if ( !rc) break; ui = (unsigned int)m_textdisplaymode; rc = file.WriteInt(ui); if ( !rc) break; // June 17, 2010 - Lowell - Added adjustment to position text // a little better in pre-v5 files. // There's no adjustment for right/left justify becasue we don't // know the width of the text here // This doesn't change the size or position of any fields being // written, but just adjusts the plane to tune up the alignment // 16 Nov, 2011 - Lowell - Change text to bottom left justified for pre-v5 files rr94270 // This stuff is moved to CRhinoDoc::Write3DMHelper() so it will help with other file // formats too //ON_Plane plane = m_plane; //if(file.Archive3dmVersion() <= 4 && m_type == ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock) //{ // double height = m_textheight; // int lines = CountTextLines(m_usertext); // double linefeed = ON_Font::m_default_linefeed_ratio; // if(m_justification & tjBottom) // { // if(lines > 1) // { // ON_3dPoint p = plane.PointAt(0.0, -height * (lines-1) * linefeed); // plane.SetOrigin(p); // } // } // else if(m_justification & tjMiddle) // { // double h = height * (lines-1) * linefeed + height; // ON_3dPoint p = plane.PointAt(0.0, h * 0.5); // plane.SetOrigin(p); // } // else if(m_justification & tjTop) // { // ON_3dPoint p = plane.PointAt(0.0, -height); // plane.SetOrigin(p); // } //} rc = file.WritePlane(m_plane); if ( !rc) break; ON_2dPointArray points = m_points; int bUserPositionedText = m_userpositionedtext?1:0; switch( m_type ) { case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: if ( 4 == points.Count() ) { // so old versions will read enough points. points.AppendNew(); points[4].Set(0.5*(points[0].x + points[2].x),points[1].y); bUserPositionedText = false; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: //user positioned text is supported. break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: // 9 August 2005 Dale Lear - radial dimensions do // not support user postioned text. The never have // in Rhino, but the old files had 5 points in them. if ( 4 == points.Count() ) { // so old versions will read enough points. points.AppendNew(); } if ( points.Count() >= 5 ) { points[4] = points[2]; } bUserPositionedText = false; break; default: bUserPositionedText = false; break; } rc = file.WriteArray( points); if ( !rc) break; // June 17, 2010 - Lowell - Added support for writing word-wrapped text // to pre-v5 files with hard returns in place of wrapping markers rc = ( file.Archive3dmVersion() <= 4 ) ? WriteAnnotation2UserText_V4(file,m_usertext) : WriteAnnotation2UserText_V5(file,m_usertext); if ( !rc) break; // 7-9-03 lw removed extra text string getting written rc = file.WriteInt( bUserPositionedText ); if ( !rc) break; const bool bIsText = IsText(); //rc = file.Write3dmReferencedComponentIndex( // bIsText ? ON_ModelComponent::Type::TextStyle : ON_ModelComponent::Type::DimStyle, m_dimstyle_index ); rc = file.WriteInt(m_v5_3dm_archive_dimstyle_index); if ( !rc) break; rc = file.WriteDouble( m_textheight); if ( !rc) break; if ( !bInChunk ) break; // NOTE WELL - NEVER change the code in this function // above this comment. If you do, you will // break reading and writing V4 files. // Ask Dale Lear if you have any questions. // 18 October 2007 - Dale Lear added m_justification IO rc = file.WriteInt(m_justification); if ( !rc) break; // 28 Aug 2010 - Lowell - Added flag for whether text gets scaled in modelspace rc = file.WriteBool(m_annotative_scale); if(!rc) break; // 24 September 2010 Dale Lear // I incremented chunk version to 1.2 ON_wString text_formula = TextFormula(); rc = file.WriteString(text_formula); if(!rc) break; // To write more ON_OBSOLETE_V5_Annotation fields, increment the minor version // number and write the new information here. // September 2015 Dale Lear // I incremented chunk version to 1.3 // and separated text style and dim style //rc = file.Write3dmReferencedComponentIndex( ON_ModelComponent::Type::TextStyle, bIsText ? m_dimstyle_index : -1 ); //if ( !rc) break; //rc = file.Write3dmReferencedComponentIndex( ON_ModelComponent::Type::DimStyle, bIsText ? -1 : m_dimstyle_index ); //if ( !rc) break; rc = file.WriteInt( bIsText ? m_v5_3dm_archive_dimstyle_index : -1 ); if ( !rc) break; rc = file.WriteInt( bIsText ? -1 : m_v5_3dm_archive_dimstyle_index ); if ( !rc) break; // Finished writing ON_OBSOLETE_V5_Annotation information break; } if ( bInChunk ) { if ( !file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_OBSOLETE_V5_Annotation::Read( ON_BinaryArchive& file ) { // NOTE WELL - If you make any changes to this code, // you break file IO for some annotation // objects. Please discuss all changes // with Dale Lear BEFORE you check in any // changes. Destroy(); // If annotation is read from old files that do not contain // the m_annotative_scale setting, then m_annotative_scale // must be false so the text behaves the way it did in old // files. The "Destroy()" function above can set m_annotative_scale // any way that makes sense for new objects. m_annotative_scale = false; int major_version = 0; int minor_version = 0; bool rc = false; bool bInChunk = (file.Archive3dmVersion() >= 5 && file.ArchiveOpenNURBSVersion() >= 200710180); if ( bInChunk ) { rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; } else { rc = file.Read3dmChunkVersion(&major_version,&minor_version); } bool bIsText = false; int dim_style_index = ON_UNSET_INT_INDEX; int dim_style_index0 = ON_UNSET_INT_INDEX; int dim_style_index1 = ON_UNSET_INT_INDEX; int dim_style_index2 = ON_UNSET_INT_INDEX; while(rc) { if ( 1 != major_version ) { rc = false; break; } unsigned int ui; rc = file.ReadInt(&ui); if (!rc) break; m_type = ON_INTERNAL_OBSOLETE::V5AnnotationTypeFromUnsigned(ui); rc = file.ReadInt(&ui); if (!rc) break; m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode(ui); rc = file.ReadPlane( m_plane); if (!rc) break; rc = file.ReadArray( m_points); if (!rc) break; rc = file.ReadString( m_usertext); if (!rc) break; ui = 0; rc = file.ReadInt( &ui ); if (!rc) break; m_userpositionedtext = ui ? true : false; // Initially, a single integer was used. It was either a text style index or a dim style index. // In August 2016, text styles were removed and font information is saved on ON_DimStyle. // When Read3dmReferencedComponentIndex() is called with the first parameter = ON_ModelComponent::Type::TextStyle, // it returns the value to use as a dimstyle index. bIsText = IsText(); rc = file.Read3dmReferencedComponentIndex( bIsText ? ON_ModelComponent::Type::TextStyle : ON_ModelComponent::Type::DimStyle, &dim_style_index0 ); if (!rc) break; dim_style_index = dim_style_index0; rc = file.ReadDouble( &m_textheight); if (!rc) break; switch( m_type ) { case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: if ( m_points.Count() < 5 ) { m_userpositionedtext = false; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: if ( m_points.Count() <= 0 ) { m_userpositionedtext = false; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: // 9 August 2005 Dale Lear - radial dimensions do // not support user postioned text. The never have // in Rhino, but the old files had 5 points in them. if ( 5 == m_points.Count() ) { m_points.SetCount(4); } m_userpositionedtext = false; break; default: m_userpositionedtext = false; break; } if ( !bInChunk ) break; // 18 October 2007 - Dale Lear added m_justification IO rc = file.ReadInt( &m_justification ); if (!rc) break; if ( minor_version <= 0 ) break; if(minor_version >= 1) { // 28 Aug, 2010 - Lowell - added reading annotative scale flag rc = file.ReadBool(&m_annotative_scale); if (!rc) break; if ( minor_version >= 2 ) { // 24 September 2010 Dale Lear // I incremented chunk version to 1.2 ON_wString text_formula; rc = file.ReadString(text_formula); if(!rc) break; SetTextFormula(static_cast< const wchar_t* >(text_formula)); if (minor_version >= 3) { // September 2015 Dale Lear // I incremented chunk version to 1.3 // and separated text style and dim style // In August 2016, text styles were removed and font information is saved on ON_DimStyle. // When Read3dmReferencedComponentIndex() is called with the first parameter = ON_ModelComponent::Type::TextStyle, // it returns the value to use as a dimstyle index. rc = file.Read3dmReferencedComponentIndex(ON_ModelComponent::Type::TextStyle, &dim_style_index1); if (!rc) break; rc = file.Read3dmReferencedComponentIndex(ON_ModelComponent::Type::DimStyle, &dim_style_index2); if (!rc) break; dim_style_index = ON_UNSET_INT_INDEX; } } } // Read new additions to ON_OBSOLETE_V5_Annotation here break; } if ( bInChunk ) { if (!file.EndRead3dmChunk() ) rc = false; } //if (!bInChunk) { // If justification is 0, change it to top-left // and move the text point up by text height if (bIsText && 0 == m_justification) { m_justification = eTextJustification::tjTopLeft; m_plane.origin = m_plane.PointAt(0.0, m_textheight); } } if (ON_UNSET_INT_INDEX == dim_style_index) { if (bIsText) { if (dim_style_index0 > ON_UNSET_INT_INDEX && dim_style_index0 == dim_style_index1) dim_style_index = dim_style_index1; else { ON_ERROR("Unexpected text object dim style index."); if (dim_style_index1 >= 0) dim_style_index = dim_style_index1; else if (dim_style_index0 >= 0) dim_style_index = dim_style_index0; else if (dim_style_index2 >= 0) dim_style_index = dim_style_index2; } } else { // not text if (dim_style_index0 > ON_UNSET_INT_INDEX && dim_style_index0 == dim_style_index2) dim_style_index = dim_style_index2; else { ON_ERROR("Unexpected dimension object dim style index."); if (dim_style_index2 >= 0) dim_style_index = dim_style_index2; else if (dim_style_index0 >= 0) dim_style_index = dim_style_index0; else if (dim_style_index1 >= 0) dim_style_index = dim_style_index1; } } } if (ON_UNSET_INT_INDEX != dim_style_index) this->SetV5_3dmArchiveDimStyleIndex( dim_style_index ); return rc; } ON::object_type ON_OBSOLETE_V5_Annotation::ObjectType() const { return ON::annotation_object; } int ON_OBSOLETE_V5_Annotation::Dimension() const { return 3; } bool ON_OBSOLETE_V5_Annotation::Transform( const ON_Xform& xform ) { ON_Geometry::Transform(xform); const double tol = 1.0e-4; ON_3dVector vx = Plane().xaxis; ON_3dVector vy = Plane().yaxis; vx.Transform(xform); vy.Transform(xform); double sx = vx.Length(); double sy = vy.Length(); if ((fabs(sx - 1.0) > tol && fabs(sx) > tol) || (fabs(sy - 1.0) > tol && fabs(sy) > tol)) { ON_Xform xfscale(ON_Xform::DiagonalTransformation(sx, sy, 1.0)); ON_2dPoint p; for (int i = 0; i < m_points.Count(); i++) { p = Point(i); p.Transform(xfscale); SetPoint(i, p); } } // This scales the text height on text but not on dimensions if (ON_OBSOLETE_V5_Annotation::IsText()) { SetHeight(sy * Height()); } return m_plane.Transform(xform); } int ON_Plane_Repair(ON_Plane& plane) { int rc; if ( plane.IsValid() ) { rc = 1; } else { rc = 2; if (!plane.origin.IsValid()) { plane.origin.Set(0.0,0.0,0.0); } bool bGoodX = (plane.xaxis.IsValid() && !plane.xaxis.IsZero() ); bool bGoodY = (plane.yaxis.IsValid() && !plane.yaxis.IsZero() ); bool bGoodZ = (plane.zaxis.IsValid() && !plane.zaxis.IsZero() ); if ( bGoodX ) { if ( fabs(plane.xaxis.Length()-1.0) > ON_SQRT_EPSILON ) plane.xaxis.Unitize(); } if ( bGoodY ) { if ( fabs(plane.yaxis.Length()-1.0) > ON_SQRT_EPSILON ) plane.yaxis.Unitize(); } if ( bGoodZ ) { if ( fabs(plane.zaxis.Length()-1.0) > ON_SQRT_EPSILON ) plane.zaxis.Unitize(); } if ( bGoodZ ) { double x = bGoodX ? fabs(plane.zaxis*plane.xaxis) : 99.0; double y = bGoodX ? fabs(plane.zaxis*plane.yaxis) : 99.0; if ( x <= ON_SQRT_EPSILON ) { if ( y > ON_SQRT_EPSILON ) { plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis); plane.yaxis.Unitize(); } } else if ( y <= ON_SQRT_EPSILON ) { plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis); plane.xaxis.Unitize(); } else if ( x <= y && x < 1.0 ) { plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis); if( plane.yaxis.Unitize() ) { plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis); plane.xaxis.Unitize(); } else if ( y < 1.0 ) { plane.CreateFromNormal( plane.origin, plane.zaxis ); } } else if ( y < 1.0 ) { plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis); if( plane.xaxis.Unitize() ) { plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis); plane.yaxis.Unitize(); } else { plane.CreateFromNormal( plane.origin, plane.zaxis ); } } } else if ( bGoodX ) { if ( bGoodY ) { plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis); if ( plane.zaxis.Unitize() ) { if ( fabs(plane.yaxis*plane.xaxis) > ON_SQRT_EPSILON ) { plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis); plane.yaxis.Unitize(); } } else { plane.yaxis.PerpendicularTo(plane.xaxis); plane.yaxis.Unitize(); plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis); plane.zaxis.Unitize(); } } else { plane.yaxis.PerpendicularTo(plane.xaxis); plane.yaxis.Unitize(); plane.zaxis = ON_CrossProduct(plane.xaxis,plane.yaxis); plane.zaxis.Unitize(); } } else if ( bGoodY ) { plane.zaxis.PerpendicularTo(plane.yaxis); plane.zaxis.Unitize(); plane.xaxis = ON_CrossProduct(plane.yaxis,plane.zaxis); plane.xaxis.Unitize(); } else { plane.xaxis.Set(1.0,0.0,0.0); plane.yaxis.Set(0.0,1.0,0.0); plane.zaxis.Set(0.0,0.0,1.0); } plane.UpdateEquation(); } return rc; } // overrides virtual ON_Geometry::Transform() bool ON_OBSOLETE_V5_DimRadial::Transform( const ON_Xform& xform ) { // TODO fill in something that works for non-rigid transforms return ON_OBSOLETE_V5_Annotation::Transform(xform); } bool ON_OBSOLETE_V5_Leader::Transform( const ON_Xform& xform ) { bool rc = xform.IsIdentity(); if ( !rc) { ON_Plane plane = m_plane; rc = plane.Transform(xform); if ( rc ) { int i; const int point_count = m_points.Count(); ON_2dPointArray q(point_count); ON_2dPoint p2, q2; ON_3dPoint P, Q; bool bUpdatePoints = false; for ( i = 0; i < point_count && rc; i++ ) { p2 = m_points[i]; P = m_plane.PointAt( p2.x, p2.y ); Q = xform*P; if( !plane.ClosestPointTo(Q,&q2.x,&q2.y) ) rc = false; if ( fabs(p2.x - q2.x) <= ON_SQRT_EPSILON ) q2.x = p2.x; else bUpdatePoints = true; if ( fabs(p2.y - q2.y) <= ON_SQRT_EPSILON ) q2.y = p2.y; else bUpdatePoints = true; q.Append(q2); } if(rc) { ON_Geometry::Transform(xform); m_plane = plane; if ( bUpdatePoints ) m_points = q; if ( m_points[0].x != 0.0 || m_points[0].y != 0.0 ) { ON_2dVector v = m_points[0]; if ( !v.IsZero() ) { m_plane.origin = m_plane.PointAt(v.x,v.y); m_plane.UpdateEquation(); v = -v; for ( i = 1; i < point_count; i++ ) { m_points[i] += v; } m_points[0].Set(0.0,0.0); } } } } } return rc; } bool ON_OBSOLETE_V5_DimAngular::Transform( const ON_Xform& xform ) { // Dale Lear - this override fixes RR 11114 by correctly // handling non uniform scaling. bool rc = xform.IsIdentity(); if ( !rc) { ON_Plane plane = m_plane; if ( dim_pt_count == m_points.Count() && plane.Transform( xform ) ) { rc = true; ON_3dPoint P[dim_pt_count], Q[dim_pt_count], A[3], B[3]; ON_2dVector p2[dim_pt_count], q2[dim_pt_count], a[3], b[3]; double r[3]; int i; bool bUpdatePoints = false; double a0 = 0.0; double a1 = m_angle; a[0].Set( m_radius*cos(a0), m_radius*sin(a0) ); a[1].Set( m_radius*cos(0.5*(a0+a1)), m_radius*sin(0.5*(a0+a1)) ); a[2].Set( m_radius*cos(a1), m_radius*sin(a1) ); for ( i = 0; i < dim_pt_count && rc; i++ ) { p2[i] = m_points[i]; P[i] = m_plane.PointAt( p2[i].x, p2[i].y ); Q[i] = xform*P[i]; if( !plane.ClosestPointTo(Q[i],&q2[i].x,&q2[i].y) ) rc = false; if ( fabs(p2[i].x - q2[i].x) > ON_SQRT_EPSILON || fabs(p2[i].y - q2[i].y) > ON_SQRT_EPSILON ) { // transformation is not a rigid motion bUpdatePoints = true; } } for ( i = 0; i < 3 && rc; i++ ) { A[i] = m_plane.PointAt( a[i].x, a[i].y ); B[i] = xform*A[i]; if( !plane.ClosestPointTo(B[i],&b[i].x,&b[i].y) ) rc = false; r[i] = B[i].DistanceTo(plane.origin); if ( fabs(a[i].x - b[i].x) > ON_SQRT_EPSILON || fabs(a[i].y - b[i].y) > ON_SQRT_EPSILON ) { // transformation is not a rigid motion bUpdatePoints = true; } if ( r[i] < ON_SQRT_EPSILON ) rc = false; else if ( r[i] > m_radius*(1.0+ON_SQRT_EPSILON) ) bUpdatePoints = true; else if ( r[i] < m_radius*(1.0-ON_SQRT_EPSILON) ) bUpdatePoints = true; } if (rc) { if ( bUpdatePoints ) { ON_3dVector X = B[0] - plane.origin; X.Unitize(); ON_3dVector Y1 = B[1] - plane.origin; Y1.Unitize(); ON_3dVector Z1 = ON_CrossProduct(X,Y1); double z1 = Z1.Length(); Z1.Unitize(); ON_3dVector Y2 = B[2] - plane.origin; Y2.Unitize(); ON_3dVector Z2 = ON_CrossProduct(X,Y2); double z2 = Z2.Length(); Z2.Unitize(); if ( z2 >= z1 && z2 >= 0.00001 ) // 4 April 2014 - Lowell - At 0.05, this was too big a tolerance { // when the dimension had previously been scaled by 0.001 etc. Rh-25926 plane.xaxis = X; plane.zaxis = Z2; if (Z1*Z2 < 0.0) plane.zaxis = -plane.zaxis; plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis); plane.yaxis.Unitize(); } else if ( z1 >= 0.00001 ) { plane.xaxis = X; plane.zaxis = Z1; plane.yaxis = ON_CrossProduct(plane.zaxis,plane.xaxis); plane.yaxis.Unitize(); } else { rc = false; } if (rc) { plane.UpdateEquation(); ON_3dVector V = B[2] - plane.origin; double x = V*plane.xaxis; double y = V*plane.yaxis; double angle = atan2(y,x); if ( angle < 0.0 ) angle += 2.0*ON_PI; double radius = (r[0]+r[1]+r[2])/3.0; double arc_pt_angle = 1.0/3.0; if ( m_angle > 0.0 && m_points[arc_pt_index].IsValid() ) { arc_pt_angle = atan2(m_points[arc_pt_index].y,m_points[arc_pt_index].x); if ( arc_pt_angle < 0.0 ) arc_pt_angle += 2.0*ON_PI; if ( arc_pt_angle > m_angle ) arc_pt_angle = 1.0/3.0; else arc_pt_angle /= m_angle; if ( arc_pt_angle < 0.0 ) arc_pt_angle = 0.0; else if ( arc_pt_angle > 1.0 ) arc_pt_angle = 1.0; } arc_pt_angle *= angle; ON_Geometry::Transform(xform); m_plane = plane; m_radius = radius; m_angle = angle; m_points[start_pt_index].Set(m_radius,0.0); m_points[end_pt_index].Set(m_radius*cos(m_angle),m_radius*sin(m_angle)); m_points[arc_pt_index].Set(m_radius*cos(arc_pt_angle),m_radius*sin(arc_pt_angle)); if ( m_userpositionedtext ) { m_plane.ClosestPointTo(Q[userpositionedtext_pt_index], &m_points[userpositionedtext_pt_index].x, &m_points[userpositionedtext_pt_index].y ); } else { m_points[userpositionedtext_pt_index].Set(m_radius*cos(0.5*m_angle),m_radius*sin(0.5*m_angle)); } } } else { ON_Geometry::Transform(xform); m_plane = plane; } } } } return rc; } bool ON_OBSOLETE_V5_Annotation::IsText() const { return (ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock == m_type); } bool ON_OBSOLETE_V5_Annotation::IsLeader() const { return (ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader == m_type); } bool ON_OBSOLETE_V5_Annotation::IsDimension() const { return (ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock != m_type && ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader != m_type); } double ON_OBSOLETE_V5_Annotation::NumericValue() const { return ON_UNSET_VALUE; } void ON_OBSOLETE_V5_Annotation::SetHeight( double ht) { if( ht > ON_SQRT_EPSILON) m_textheight = ht; } double ON_OBSOLETE_V5_Annotation::Height() const { return m_textheight; } void ON_OBSOLETE_V5_Annotation::SetType( ON_INTERNAL_OBSOLETE::V5_eAnnotationType type ) { m_type = type; if(type == ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius) SetTextValue(ON_OBSOLETE_V5_DimRadial::DefaultRadiusText()); else if(type == ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter) SetTextValue(ON_OBSOLETE_V5_DimRadial::DefaultDiameterText()); else SetTextValue(0); SetTextFormula(0); } ON_INTERNAL_OBSOLETE::V5_eAnnotationType ON_OBSOLETE_V5_Annotation::Type() const { return m_type; } void ON_OBSOLETE_V5_Annotation::SetPlane( const ON_Plane& plane ) { m_plane = plane; } const ON_Plane& ON_OBSOLETE_V5_Annotation::Plane() const { return m_plane; } void ON_OBSOLETE_V5_Annotation::SetPointCount( int count) { if( m_points.Count() < count) { m_points.Reserve( count); for( int i = m_points.Count(); i < count; i++) m_points.Append( ON_2dPoint()); } } int ON_OBSOLETE_V5_Annotation::PointCount() const { return m_points.Count(); } void ON_OBSOLETE_V5_Annotation::SetPoints( const ON_2dPointArray& points ) { m_points = points; } const ON_2dPointArray& ON_OBSOLETE_V5_Annotation::Points() const { return m_points; } void ON_OBSOLETE_V5_Annotation::SetPoint( int idx, const ON_2dPoint& point ) { if ( idx >= 0 ) { if ( idx < m_points.Count() ) m_points[idx] = point; else if ( idx == m_points.Count() ) m_points.Append(point); } } ON_2dPoint ON_OBSOLETE_V5_Annotation::Point( int idx ) const { return ( idx >= 0 && idx < m_points.Count() ) ? m_points[idx] : ON_2dPoint( 0.0, 0.0 ); } void ON_OBSOLETE_V5_Annotation::SetUserText( const wchar_t* text_value ) // ON_OBSOLETE_V5_Annotation::SetUserText is OBSOLETE - use ON_OBSOLETE_V5_Annotation::SetTextValue(); { SetTextValue( text_value ); } const ON_wString& ON_OBSOLETE_V5_Annotation::UserText() const // ON_OBSOLETE_V5_Annotation::UserText() is OBSOLETE - use ON_OBSOLETE_V5_Annotation::TextValue(); { return m_usertext; } void ON_OBSOLETE_V5_Annotation::SetUserPositionedText( int bMoved ) { m_userpositionedtext = bMoved?true:false; } bool ON_OBSOLETE_V5_Annotation::UserPositionedText() const { return m_userpositionedtext; } // Converts 2d points in annotation to 3d WCS points bool ON_OBSOLETE_V5_Annotation::GetECStoWCSXform( ON_Xform& xform ) const { ON_3dVector z = ON_CrossProduct( m_plane.xaxis, m_plane.yaxis ); return xform.ChangeBasis( m_plane.origin, m_plane.xaxis, m_plane.yaxis, z, ON_3dPoint::Origin, ON_3dVector::XAxis, ON_3dVector::YAxis, ON_3dVector::ZAxis ); } // Converts from WCS 3d points to 2d points in annotation bool ON_OBSOLETE_V5_Annotation::GetWCStoECSXform( ON_Xform& xform ) const { ON_3dVector z = ON_CrossProduct( m_plane.xaxis, m_plane.yaxis ); return xform.ChangeBasis( ON_3dPoint::Origin, ON_3dVector::XAxis, ON_3dVector::YAxis, ON_3dVector::ZAxis, m_plane.origin, m_plane.xaxis, m_plane.yaxis, z ); } void ON_OBSOLETE_V5_Annotation::ReservePoints( int count) { m_points.SetCapacity( count); m_points.SetCount( count); } const wchar_t* ON_OBSOLETE_V5_Annotation::DefaultText() { return L""; } void ON_OBSOLETE_V5_Annotation::SetTextDisplayMode( ON_INTERNAL_OBSOLETE::V5_TextDisplayMode mode) { m_textdisplaymode = mode; } ON_INTERNAL_OBSOLETE::V5_TextDisplayMode ON_OBSOLETE_V5_Annotation::TextDisplayMode() const { return m_textdisplaymode; } void ON_OBSOLETE_V2_Annotation::Internal_InitializeFromV5Annotation( const ON_OBSOLETE_V5_Annotation& V5_annotation, const class ON_3dmAnnotationContext* annotation_context ) { SetType( V5_annotation.Type()); SetTextDisplayMode( V5_annotation.TextDisplayMode()); SetPlane( V5_annotation.Plane()); SetPoints( V5_annotation.Points()); SetUserText( V5_annotation.TextValue()); SetDefaultText( V5_annotation.DefaultText()); SetUserPositionedText( V5_annotation.UserPositionedText()); } void ON_OBSOLETE_V5_Annotation::SetJustification( unsigned int justification) { if(this->IsLeader()) m_justification = justification; } unsigned int ON_OBSOLETE_V5_Annotation::Justification() const { if(this->IsLeader()) return m_justification; else return 0; } //----- ON_OBSOLETE_V5_DimLinear ------------------------------------------ ON_OBSOLETE_V5_DimLinear::ON_OBSOLETE_V5_DimLinear() { //ON_OBSOLETE_V5_DimExtra* pDE = new ON_OBSOLETE_V5_DimExtra; //if( pDE) //{ // if( !AttachUserData( pDE)) // delete pDE; // else // pDE->SetDefaults(); //} m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear; m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine; m_plane = ON_xy_plane; SetTextValue(DefaultText()); SetTextFormula(0); m_points.Reserve(ON_OBSOLETE_V5_DimLinear::dim_pt_count); m_points.SetCount(ON_OBSOLETE_V5_DimLinear::dim_pt_count); m_points.Zero(); } ON_OBSOLETE_V5_DimLinear::~ON_OBSOLETE_V5_DimLinear() { } bool ON_OBSOLETE_V5_DimLinear::IsValid( ON_TextLog* text_log ) const { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear && m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimLinear - m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear or ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned.\n"); } return false; } if ( !ON_OBSOLETE_V5_Annotation::IsValid( text_log )) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimLinear - invalid ON_OBSOLETE_V5_Annotation base class.\n"); } return false; } if ( m_points.Count() != 5 ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimLinear - m_points.Count() = %d (should be 5).\n",m_points.Count()); } return false; } if ( m_points[1].x != m_points[0].x ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimLinear - m_points[1].x = %g != %g = m_points[0].x (should be equal)\n", m_points[1].x, m_points[0].x ); } return false; } if ( m_points[3].x != m_points[2].x ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimLinear - m_points[3].x = %g != %g = m_points[2].x\n", m_points[3].x, m_points[2].x ); } return false; } if ( m_points[3].y != m_points[1].y ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimLinear - m_points[3].y = %g != %g = m_points[1].y\n", m_points[3].y, m_points[1].y ); } return false; } return true; } bool ON_OBSOLETE_V5_DimLinear::Write(ON_BinaryArchive& archive) const { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_DimLinear // V4 did not have a ON_OBSOLETE_V5_DimLinear::Write and simply called // ON_OBSOLETE_V5_Annotation::Write. bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5); if ( bInChunk ) { rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Write(archive)?true:false; if (!rc) break; if ( !bInChunk ) break; // To write new fields, increment minor version number // and write values here. Ask Dale Lear for help. break; } if ( bInChunk ) { if (!archive.EndWrite3dmChunk()) rc = false; } return rc; } bool ON_OBSOLETE_V5_DimLinear::Read(ON_BinaryArchive& archive) { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_DimLinear int major_version = 0; int minor_version = 0; bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180); if ( bInChunk ) { rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Read(archive)?true:false; if (!rc) break; if ( !bInChunk || minor_version <= 0 ) break; // read future addition here break; } if ( bInChunk ) { if ( !archive.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_OBSOLETE_V5_DimLinear::GetBBox( double* boxmin, double* boxmax, bool bGrowBox ) const { ON_BoundingBox bbox; if ( bGrowBox ) { bbox.m_min.x = boxmin[0]; bbox.m_min.y = boxmin[1]; bbox.m_min.z = boxmin[2]; bbox.m_max.x = boxmax[0]; bbox.m_max.y = boxmax[1]; bbox.m_max.z = boxmax[2]; if ( !bbox.IsValid() ) { bbox.Destroy(); bGrowBox = false; } } if ( 5 == m_points.Count() ) { ON_3dPointArray P(5); ON_2dPoint uv; if ( m_userpositionedtext ) { uv = m_points[0]; // point someplace in text P.Append( m_plane.PointAt(uv.x,uv.y) ); } P.Append( m_plane.origin ); uv.x = 0.0; uv.y = m_points[1].y; P.Append( m_plane.PointAt(uv.x,uv.y) ); uv = m_points[2]; P.Append( m_plane.PointAt(uv.x,uv.y) ); uv.y = m_points[1].y; P.Append( m_plane.PointAt(uv.x,uv.y) ); bGrowBox = P.GetBBox(&bbox.m_min.x, &bbox.m_max.x, bGrowBox); } if ( bGrowBox ) { boxmin[0] = bbox.m_min.x; boxmin[1] = bbox.m_min.y; boxmin[2] = bbox.m_min.z; boxmax[0] = bbox.m_max.x; boxmax[1] = bbox.m_max.y; boxmax[2] = bbox.m_max.z; } return bGrowBox; } bool ON_OBSOLETE_V5_DimLinear::GetTightBoundingBox( ON_BoundingBox& tight_bbox, bool bGrowBox, const ON_Xform* xform ) const { if ( 5 == m_points.Count() ) { ON_3dPointArray P(5); // 18 Oct 2012 - Lowell - Fixed this to add all of the points to the bbox rr116270 for(int i = 0; i < 5; i++) P.Append( m_plane.PointAt(m_points[i].x,m_points[i].y) ); if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) ) bGrowBox = true; } else if ( bGrowBox && !tight_bbox.IsValid() ) { tight_bbox.Destroy(); bGrowBox = false; } return (0!=bGrowBox); } int ON_OBSOLETE_V5_DimLinear::Repair() { // returns 0 = unable to repair // 1 = in perfect condtion // 2 == repaired. const int ext0_pt_index = ON_OBSOLETE_V5_DimLinear::ext0_pt_index; const int arrow0_pt_index = ON_OBSOLETE_V5_DimLinear::arrow0_pt_index; const int ext1_pt_index = ON_OBSOLETE_V5_DimLinear::ext1_pt_index; const int arrow1_pt_index = ON_OBSOLETE_V5_DimLinear::arrow1_pt_index; const int userpositionedtext_pt_index = ON_OBSOLETE_V5_DimLinear::userpositionedtext_pt_index; const int dim_pt_count = ON_OBSOLETE_V5_DimLinear::dim_pt_count; int rc = 0; if ( m_points.Count() >= dim_pt_count && m_points[ext0_pt_index].IsValid() && m_points[ext1_pt_index].IsValid() ) { rc = 1; if ( !m_plane.IsValid() ) { rc = ON_Plane_Repair(m_plane); } if ( m_points.Count() > dim_pt_count ) { rc = 2; m_points.SetCount(dim_pt_count); } // m_points[ext0_pt_index] must be at (0,0) ON_2dVector v = m_points[ext0_pt_index]; double d; int i; if ( !v.IsZero() ) { rc = 2; m_plane.origin = m_plane.PointAt(v.x,v.y); m_plane.UpdateEquation(); v = -v; for ( i = 0; i < dim_pt_count; i++ ) { m_points[i] += v; } m_points[ext0_pt_index].Set(0.0,0.0); } if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned == m_type && (m_points[ext1_pt_index].x < 0.0 || m_points[ext1_pt_index].y != 0.0) ) { rc = 2; // Aligned dims must have m_points[ext1_pt_index].x = m_points[ext0_pt_index].x if ( m_points[ext1_pt_index].x > 100.0*ON_SQRT_EPSILON && fabs(m_points[ext1_pt_index].y) <= ON_SQRT_EPSILON ) { m_points[ext1_pt_index].y = 0.0; } else { // Dimension line parallel to point0 -> point2 // rotate the plane so p2 is on the x axis v = m_points[ext1_pt_index]; d = v.Length(); v.Unitize(); m_plane.Rotate(v.y,v.x,m_plane.zaxis,m_plane.origin); // rotate points in opposite direction v.y = -v.y; for ( i = 0; i < dim_pt_count; i++ ) { ON_2dPoint p = m_points[i]; m_points[i].Set( v.x*p.x - v.y*p.y, v.y*p.x + v.x*p.y ); } m_points[ext0_pt_index].Set(0.0,0.0); m_points[ext1_pt_index].Set(d,0.0); } } else if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear != m_type ) { rc = 2; m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear; } if ( m_points[arrow0_pt_index].x != m_points[ext0_pt_index].x ) { rc = 2; m_points[arrow0_pt_index].x = m_points[ext0_pt_index].x; } if ( m_points[arrow1_pt_index].x != m_points[ext1_pt_index].x ) { rc = 2; m_points[arrow1_pt_index].x = m_points[ext1_pt_index].x; } if ( !ON_IsValid(m_points[arrow0_pt_index].y) ) { rc = 2; if ( !ON_IsValid(m_points[arrow1_pt_index].y) ) m_points[arrow1_pt_index].y = 0.5*(m_points[ext0_pt_index].y + m_points[ext1_pt_index].y); m_points[arrow0_pt_index].y = m_points[arrow1_pt_index].y; } else if ( !ON_IsValid(m_points[arrow1_pt_index].y) ) { rc = 2; m_points[arrow1_pt_index].y = m_points[arrow0_pt_index].y; } else if ( m_points[arrow0_pt_index].y != m_points[arrow1_pt_index].y ) { rc = 2; d = 0.5*(m_points[arrow0_pt_index].y + m_points[arrow1_pt_index].y); m_points[arrow0_pt_index].y = d; m_points[arrow1_pt_index].y = d; } if ( m_userpositionedtext ) { if ( !m_points[userpositionedtext_pt_index].IsValid() ) { rc = 2; m_userpositionedtext = false; } } if ( !m_userpositionedtext ) { if ( m_points[userpositionedtext_pt_index].y != m_points[arrow0_pt_index].y || m_points[userpositionedtext_pt_index].x != 0.5*(m_points[arrow0_pt_index].x + m_points[arrow1_pt_index].x) ) { rc = 2; m_points[userpositionedtext_pt_index].y = m_points[arrow0_pt_index].y; m_points[userpositionedtext_pt_index].x = 0.5*(m_points[arrow0_pt_index].x + m_points[arrow1_pt_index].x); } } if ( !m_plane.IsValid() ) { rc = 2; ON_Plane_Repair(m_plane); } } return rc; } bool ON_OBSOLETE_V5_DimLinear::Transform( const ON_Xform& xform ) { // Dale Lear - this override fixes RR 11114 by correctly // handling non uniform scaling. bool rc = xform.IsIdentity(); if ( !rc) { ON_Plane plane = m_plane; if ( dim_pt_count == m_points.Count() && plane.Transform( xform ) ) { rc = true; ON_3dPoint P[dim_pt_count], Q[dim_pt_count]; ON_2dVector p2[dim_pt_count], q2[dim_pt_count]; int i; bool bUpdatePoints = false; for ( i = 0; i < dim_pt_count && rc; i++ ) { p2[i] = m_points[i]; P[i] = m_plane.PointAt( p2[i].x, p2[i].y ); Q[i] = xform*P[i]; if( !plane.ClosestPointTo(Q[i],&q2[i].x,&q2[i].y) ) rc = false; if ( fabs(p2[i].x - q2[i].x) > ON_SQRT_EPSILON || fabs(p2[i].y - q2[i].y) > ON_SQRT_EPSILON ) { // transformation is not in SL3 bUpdatePoints = true; } } if (rc) { ON_Geometry::Transform(xform); m_plane = plane; if ( bUpdatePoints ) { for ( i = 0; i < dim_pt_count && rc; i++ ) { m_points[i] = q2[i]; } // Repair() will properly align the arrow points, etc. Repair(); } } } } return rc; } double ON_OBSOLETE_V5_DimLinear::NumericValue() const { // Use y coords of ext points instead of 3d distance // to reduce noise in the answer. return (m_points.Count() >= dim_pt_count) ? fabs(m_points[ext0_pt_index].x - m_points[ext1_pt_index].x) : 0.0; } int ON_OBSOLETE_V5_DimLinear::StyleIndex() const { return ON_OBSOLETE_V5_Annotation::V5_3dmArchiveDimStyleIndex(); } void ON_OBSOLETE_V5_DimLinear::SetStyleIndex( int i) { ON_OBSOLETE_V5_Annotation::SetV5_3dmArchiveDimStyleIndex( i); } /* ext0_pt_index = 0, // end of first extension line arrow0_pt_index = 1, // arrowhead tip on first extension line ext1_pt_index = 2, // end of second extension line arrow1_pt_index = 3, // arrowhead tip on second extension line dim_pt_count = 5, // number of m_points[] in an angular dim // Points calculated from values in m_points[] text_pivot_pt = 10000 // center of dimension text dim_mid_pt = 10001 // midpoint of dimension line */ ON_2dPoint ON_OBSOLETE_V5_DimLinear::Dim2dPoint( int point_index ) const { ON_2dPoint p2; if ( m_points.Count() < dim_pt_count ) { p2.x = p2.y = ON_UNSET_VALUE; } else { if ( text_pivot_pt == point_index ) { point_index = m_userpositionedtext ? userpositionedtext_pt_index : dim_mid_pt; } const ON_2dPoint* points = m_points.Array(); switch(point_index) { case ext0_pt_index: p2 = points[0]; break; case arrow0_pt_index: p2.x = points[0].x; p2.y = points[1].y; break; case ext1_pt_index: p2 = points[2]; break; case arrow1_pt_index: p2.x = points[2].x; p2.y = points[1].y; break; case userpositionedtext_pt_index: p2.x = points[4].x; p2.y = points[4].y; break; case dim_mid_pt: p2.x = 0.5*(points[0].x + points[2].x); p2.y = points[1].y; break; default: p2.x = p2.y = ON_UNSET_VALUE; break; } } return p2; } ON_3dPoint ON_OBSOLETE_V5_DimLinear::Dim3dPoint( int point_index ) const { ON_2dPoint p2 = Dim2dPoint(point_index); return (ON_UNSET_VALUE == p2.x) ? ON_3dPoint::UnsetPoint : m_plane.PointAt(p2.x,p2.y); } ON_OBSOLETE_V2_TextObject* ON_OBSOLETE_V2_TextObject::CreateFromV5TextObject( const class ON_OBSOLETE_V5_TextObject& V5_text_object, const ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V2_TextObject* destination ) { if (nullptr == annotation_context) annotation_context = &ON_3dmAnnotationContext::Default; const ON_DimStyle& dim_style = annotation_context->DimStyle(); ON_OBSOLETE_V2_TextObject* V2_text_object = (nullptr != destination) ? destination : new ON_OBSOLETE_V2_TextObject(); V2_text_object->Internal_InitializeFromV5Annotation(V5_text_object,annotation_context); V2_text_object->m_facename = dim_style.Font().WindowsLogfontName(); const double V5_text_height = V5_text_object.Height(); V2_text_object->m_fontweight = 400; V2_text_object->m_height = V5_text_height; if (V2_text_object->m_plane.IsValid()) { // 8-20-03 lw convert from lower-left to upper-left reference point V2_text_object->m_plane.origin += V2_text_object->m_plane.yaxis * 1.1 * V5_text_height; V2_text_object->m_plane.UpdateEquation(); } return V2_text_object; } ON_OBSOLETE_V2_DimAngular* ON_OBSOLETE_V2_DimAngular::CreateFromV5AngularDimension( const class ON_OBSOLETE_V5_DimAngular& V5_angular_dimension, const ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V2_DimAngular* destination ) { ON_OBSOLETE_V2_DimAngular* V2_angular_dimension = (nullptr != destination) ? destination : new ON_OBSOLETE_V2_DimAngular(); V2_angular_dimension->Internal_InitializeFromV5Annotation(V5_angular_dimension,annotation_context); ON_SimpleArray V5_points(V5_angular_dimension.m_points); V2_angular_dimension->m_points.SetCount(0); V2_angular_dimension->SetPoint(0, ON_3dPoint(V5_angular_dimension.Point(1))); V2_angular_dimension->SetPoint(1, ON_3dPoint(V5_angular_dimension.Point(2))); V2_angular_dimension->SetPoint(2, ON_3dPoint(V5_angular_dimension.Point(3))); V2_angular_dimension->SetPoint(3, ON_3dPoint(V5_angular_dimension.Point(0))); // text point or apex V2_angular_dimension->SetAngle( V5_angular_dimension.Angle()); V2_angular_dimension->SetRadius( V5_angular_dimension.Radius()); return V2_angular_dimension; } ON_OBSOLETE_V2_DimRadial* ON_OBSOLETE_V2_DimRadial::CreateFromV5RadialDimension( const class ON_OBSOLETE_V5_DimRadial& V5_linear_dimension, const ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V2_DimRadial* destination ) { ON_OBSOLETE_V2_DimRadial* V2_radial_dimension = (nullptr != destination) ? destination : new ON_OBSOLETE_V2_DimRadial(); V2_radial_dimension->Internal_InitializeFromV5Annotation(V5_linear_dimension,annotation_context); return V2_radial_dimension; } ON_OBSOLETE_V2_DimLinear* ON_OBSOLETE_V2_DimLinear::CreateFromV5LinearDimension( const class ON_OBSOLETE_V5_DimLinear& V5_linear_dimension, const ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V2_DimLinear* destination ) { ON_OBSOLETE_V2_DimLinear* V2_linear_dimension = (nullptr != destination) ? destination : new ON_OBSOLETE_V2_DimLinear(); V2_linear_dimension->Internal_InitializeFromV5Annotation(V5_linear_dimension,annotation_context); return V2_linear_dimension; } ON_OBSOLETE_V5_DimLinear* ON_OBSOLETE_V5_DimLinear::CreateFromV2LinearDimension( const class ON_OBSOLETE_V2_DimLinear& V2_linear_dimension, const ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V5_DimLinear* destination ) { ON_OBSOLETE_V5_DimLinear* V5_linear_dimension = (nullptr != destination) ? destination : new ON_OBSOLETE_V5_DimLinear(); V5_linear_dimension->Internal_InitializeFromV2Annotation(V2_linear_dimension,annotation_context); return V5_linear_dimension; } int ON_OBSOLETE_V5_DimLinear::GetDimensionLineSegments( ON_OBSOLETE_V5_RECT gdi_text_rect, int gdi_height_of_I, ON_Xform gdi_to_world, const ON_DimStyle& dimstyle, double dimscale, const ON_Viewport* vp, double x[6], bool& bInside ) const { int rc = 0; x[0] = 0.0; x[1] = 0.0; x[2] = 0.0; x[3] = 0.0; x[4] = 0.0; x[5] = 0.0; bInside = true; if ( m_points.Count() < 3 ) return 0; int i = (m_points[ext0_pt_index].x <= m_points[ext1_pt_index].x) ? ext0_pt_index : ext1_pt_index; const double x0 = m_points[i].x; const double x1 = m_points[(ext0_pt_index==i) ? ext1_pt_index : ext0_pt_index].x; x[0] = x0; // left end of first dimension line x[1] = x1; // right end of first dimension line x[2] = x0; // left end of second dimension line x[3] = x1; // right end of second dimension line x[4] = x0; // tip of first arrow x[5] = x1; // tip of second arrow if ( 0 == gdi_height_of_I ) { // Default to height of Ariel 'I' gdi_height_of_I = (165*ON_Font::Constants::AnnotationFontCellHeight)/256; } if ( 0.0 == dimscale ) { dimscale = 1.0; } double t; ON_INTERNAL_OBSOLETE::V5_TextDisplayMode textdisplay = ON_INTERNAL_OBSOLETE::V5TextDisplayModeFromV6DimStyle(dimstyle); const double text_height_of_I = dimscale*dimstyle.TextHeight(); const double textgap = fabs(dimscale*dimstyle.TextGap()); const double gdi_to_plane_scale = text_height_of_I/gdi_height_of_I; const double textwidth = fabs(gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left)); const double arrowwidth = dimscale*dimstyle.ArrowSize(); const double tailwidth = 0.5*arrowwidth; const double dimwidth = x1 - x0; const double mindimwidth = (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine == textdisplay) ? (2.0*(arrowwidth + tailwidth + textgap) + textwidth) : (2.0*arrowwidth + tailwidth); const double dimextension = dimscale*dimstyle.DimExtension(); int ForceArrows = 0; const ON_OBSOLETE_V5_DimExtra* pDE = ON_OBSOLETE_V5_DimExtra::DimensionExtension(this,false); if( pDE) ForceArrows = pDE->ArrowPosition(); // 19 Apr 2012 - Lowell - Fixed so forcing arrows inside won't cause the dim line to // draw through InLine text rr103322 if(ForceArrows == -1 || // force outside (dimwidth < mindimwidth && ForceArrows != 1)) // arrowheads have to be "outside" - they won't fit inside even without text { t = arrowwidth + tailwidth; x[0] = x0; x[1] = x0-t; x[2] = x1+t; x[3] = x1; x[4] = x0; // arrow tips x[5] = x1; if( dimextension != 0.0) { x[0] += dimextension; x[3] -= dimextension; } bInside = false; rc = 2; } // Horizontal text or Userpositioned text else if ((ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen == textdisplay && vp) || m_userpositionedtext) { // use projected rectangle to clip dimension line double xx0, xx1, xx, y0, y1; ON_3dPoint P, R; ON_2dPoint corners[4]; // corners of text rect in plane coords ON_Line ray; ON_3dVector vp_zaxis = (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen == textdisplay && vp) ? vp->CameraZ() : m_plane.zaxis; // 30 July 2012 - Lowell - Slightly shrink the text gap value // so that text + gap won't intersect the dim line if when text // is moved along the dim line. rr110504 double gdi_gap = fabs(textgap/gdi_to_plane_scale)-12; if(gdi_gap < 0.0) gdi_gap = 0.0; R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[0].x,&corners[0].y); R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[1].x,&corners[1].y); R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.top-gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[2].x,&corners[2].y); R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.top-gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[3].x,&corners[3].y); // Test if text rect intersects dimension line xx0 = xx1 = ON_UNSET_VALUE; for ( i = 0; i < 4; i++ ) { y0 = corners[i].y - m_points[1].y; // vertical dist from corner to dimension line y1 = corners[(i+1)%4].y - m_points[1].y; // vertical dist from next corner to dimension line // if they're both above or both below, no intersection of this segment if ( (y0 > 0.0 && y1 > 0.0) || (y0 < 0.0 && y1 < 0.0) || y0 == y1 ) continue; // segment intersects dimension line. // find x-coord of intersection t = y0/(y0-y1); xx = (1.0-t)*corners[i].x + t*corners[(i+1)%4].x; if ( ON_UNSET_VALUE == xx0 ) { xx0 = xx1 = xx; } else if ( xx < xx0 ) { xx0 = xx; } else if ( xx > xx1 ) { xx1 = xx; } } // Nov 4 2009 - Lowell - Added test for no intersection of text with dimension line rr33003 // Important for user positioned text that's moved out of the way of the dimension line if(xx0 != ON_UNSET_VALUE && xx1 != ON_UNSET_VALUE) { // xx0 is left edge of text rect // xx1 is right edge of text rect t = arrowwidth + tailwidth; if ( x0 + t <= xx0 && xx0 < xx1 && xx1 <= x1 - t ) { // clip line, 2 segments arrows inside x[0] = x0; x[1] = xx0; x[2] = xx1; x[3] = x1; x[4] = x0; x[5] = x1; if( dimextension != 0.0) { x[0] -= dimextension; x[3] += dimextension; } rc = 2; } else // 2 segments, put the arrows outside the extension lines { x[0] = x0; x[1] = x0 - t; x[2] = x1 + t; x[3] = x1; x[4] = x0; x[5] = x1; if( dimextension != 0.0) { x[0] += dimextension; x[3] -= dimextension; } bInside = false; rc = 2; } } else { // 1 segment, arrows inside x[0] = x0; x[1] = x1; x[2] = x0; x[3] = x1; x[4] = x0; x[5] = x1; if( dimextension != 0.0) { x[0] -= dimextension; x[1] += dimextension; } rc = 1; } } // Above line text else if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine == textdisplay || m_userpositionedtext) { // 1 segment, arrows inside x[0] = x0; x[1] = x1; x[2] = x0; x[3] = x1; x[4] = x0; x[5] = x1; if( dimextension != 0.0) { x[0] -= dimextension; x[1] += dimextension; } rc = 1; } // In line text else if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine == textdisplay) { // 2 segments, arrows inside t = 0.5*(dimwidth - textwidth - 2.0*textgap); x[0] = x0; x[1] = x0+t; x[2] = x1-t; x[3] = x1; x[4] = x0; x[5] = x1; if( dimextension != 0.0) { x[0] -= dimextension; x[3] += dimextension; } rc = 2; } return rc; } const wchar_t* ON_OBSOLETE_V5_DimLinear::DefaultText() { return L"<>"; } //----- ON_OBSOLETE_V5_DimRadial ------------------------------------------ ON_OBSOLETE_V5_DimRadial::ON_OBSOLETE_V5_DimRadial() { m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter; m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine; SetTextValue(DefaultDiameterText()); SetTextFormula(0); m_points.Reserve(ON_OBSOLETE_V5_DimRadial::dim_pt_count); m_points.SetCount(ON_OBSOLETE_V5_DimRadial::dim_pt_count); m_points.Zero(); } ON_OBSOLETE_V5_DimRadial* ON_OBSOLETE_V5_DimRadial::CreateFromV2RadialDimension( const class ON_OBSOLETE_V2_DimRadial& V2_radial_dimension, const class ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V5_DimRadial* destination ) { ON_OBSOLETE_V5_DimRadial* V5_radial_dimension = (nullptr != destination) ? destination : new ON_OBSOLETE_V5_DimRadial(); V5_radial_dimension->Internal_InitializeFromV2Annotation(V2_radial_dimension,annotation_context); return V5_radial_dimension; } bool ON_OBSOLETE_V5_DimRadial::IsValid( ON_TextLog* text_log ) const { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius && m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimRadial - m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius or ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter\n"); } return false; } if ( !ON_OBSOLETE_V5_Annotation::IsValid( text_log )) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimRadial - invalid ON_OBSOLETE_V5_Annotation base class.\n"); } return false; } if ( 4 != m_points.Count() ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimRadial - m_points.Count() = %d (should be 4 or 5)\n", m_points.Count() ); } return false; } return true; } bool ON_OBSOLETE_V5_DimRadial::Write(ON_BinaryArchive& archive) const { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_DimRadial // V4 did not have a ON_OBSOLETE_V5_DimRadial::Write and simply called // ON_OBSOLETE_V5_Annotation::Write. bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5); if ( bInChunk ) { rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Write(archive)?true:false; if (!rc) break; if ( !bInChunk ) break; // To write new fields, increment minor version number // and write values here. Ask Dale Lear for help. break; } if ( bInChunk ) { if (!archive.EndWrite3dmChunk()) rc = false; } return rc; } bool ON_OBSOLETE_V5_DimRadial::Read(ON_BinaryArchive& archive) { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_DimRadial int major_version = 0; int minor_version = 0; bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180); if ( bInChunk ) { rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Read(archive)?true:false; if (!rc) break; if ( !bInChunk || minor_version <= 0 ) break; // read future addition here break; } if ( bInChunk ) { if ( !archive.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_OBSOLETE_V5_DimRadial::GetBBox( double* boxmin, double* boxmax, bool bGrowBox ) const { ON_BoundingBox bbox; if ( bGrowBox ) { bbox.m_min.x = boxmin[0]; bbox.m_min.y = boxmin[1]; bbox.m_min.z = boxmin[2]; bbox.m_max.x = boxmax[0]; bbox.m_max.y = boxmax[1]; bbox.m_max.z = boxmax[2]; if ( !bbox.IsValid() ) { bbox.Destroy(); bGrowBox = false; } } if ( 4 == m_points.Count() ) { ON_3dPointArray P(4); ON_2dPoint uv; if ( m_userpositionedtext ) { uv = m_points[0]; // point someplace in text P.Append( m_plane.PointAt(uv.x,uv.y) ); } P.Append( m_plane.origin ); // + sign at center of dimension uv = m_points[1]; P.Append( m_plane.PointAt(uv.x,uv.y) ); uv = m_points[2]; P.Append( m_plane.PointAt(uv.x,uv.y) ); uv = m_points[3]; P.Append( m_plane.PointAt(uv.x,uv.y) ); bGrowBox = P.GetBBox(&bbox.m_min.x, &bbox.m_max.x, bGrowBox); } if ( bGrowBox ) { boxmin[0] = bbox.m_min.x; boxmin[1] = bbox.m_min.y; boxmin[2] = bbox.m_min.z; boxmax[0] = bbox.m_max.x; boxmax[1] = bbox.m_max.y; boxmax[2] = bbox.m_max.z; } return bGrowBox; } bool ON_OBSOLETE_V5_DimRadial::GetTightBoundingBox( ON_BoundingBox& tight_bbox, bool bGrowBox, const ON_Xform* xform ) const { if ( 4 == m_points.Count() ) { ON_3dPointArray P(4); for(int i = 0; i < 4; i++) P.Append( m_plane.PointAt(m_points[i].x,m_points[i].y) ); if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) ) bGrowBox = true; } else if ( bGrowBox && !tight_bbox.IsValid() ) { tight_bbox.Destroy(); bGrowBox = false; } return (0!=bGrowBox); } ON_2dPoint ON_OBSOLETE_V5_DimRadial::Dim2dPoint( int point_index ) const { ON_2dPoint p2; if ( m_points.Count() < dim_pt_count || point_index < 0 ) { p2.x = p2.y = ON_UNSET_VALUE; } else { if ( text_pivot_pt == point_index ) { point_index = tail_pt_index; } if ( point_index < dim_pt_count ) { p2 = m_points[point_index]; } else { p2.x = p2.y = ON_UNSET_VALUE; } } return p2; } ON_3dPoint ON_OBSOLETE_V5_DimRadial::Dim3dPoint( int point_index ) const { ON_2dPoint p2 = Dim2dPoint(point_index); return (ON_UNSET_VALUE == p2.x) ? ON_3dPoint::UnsetPoint : m_plane.PointAt(p2.x,p2.y); } // set the plane, center, and point on curve. // the rest will be set by the Rhino dimension bool ON_OBSOLETE_V5_DimRadial::CreateFromPoints( ON_3dPoint center, ON_3dPoint arrowtip, ON_3dVector xaxis, ON_3dVector normal, double offset_distance) { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter ) m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius; bool rc = false; if ( center.IsValid() && arrowtip.IsValid() && normal.IsValid() && !normal.IsZero() && xaxis.IsValid() && !xaxis.IsZero() ) { ON_Plane plane( center, normal); double c = xaxis*plane.xaxis; double s = xaxis*plane.yaxis; if ( c != 0.0 || s != 0.0 ) { if ( c <= 0.0 || s != 0.0 ) { plane.Rotate( s, c, plane.zaxis ); } m_plane = plane; ON_2dVector tip; if ( m_plane.ClosestPointTo(arrowtip,&tip.x,&tip.y) ) { //double r = tip.Length(); m_points.SetCapacity(dim_pt_count); m_points.SetCount(dim_pt_count); m_points[center_pt_index].Set(0.0,0.0); m_points[arrow_pt_index] = tip; tip.Unitize(); m_points[knee_pt_index] = m_points[arrow_pt_index] + offset_distance*tip; m_points[tail_pt_index] = m_points[knee_pt_index]; if ( m_points[arrow_pt_index].x < 0.0 ) m_points[tail_pt_index].x -= offset_distance; else m_points[tail_pt_index].x += offset_distance; m_plane = plane; m_userpositionedtext = false; rc = true; } } } return rc; } double ON_OBSOLETE_V5_DimRadial::NumericValue() const { double d = 0.0; if ( m_points.Count() >= dim_pt_count ) { d = (m_points[center_pt_index] - m_points[arrow_pt_index]).Length(); if( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter == m_type ) d *= 2.0; } return d; } int ON_OBSOLETE_V5_DimRadial::StyleIndex() const { return ON_OBSOLETE_V5_Annotation::V5_3dmArchiveDimStyleIndex(); } void ON_OBSOLETE_V5_DimRadial::SetStyleIndex( int i) { ON_OBSOLETE_V5_Annotation::SetV5_3dmArchiveDimStyleIndex( i); } const wchar_t* ON_OBSOLETE_V5_DimRadial::DefaultRadiusText() { static wchar_t defstr[4] = { ON_wString::RadiusSymbol, L'<', L'>', 0 }; return defstr; } const wchar_t* ON_OBSOLETE_V5_DimRadial::DefaultDiameterText() { static wchar_t defstr[4] = { ON_wString::DiameterSymbol, L'<', L'>', 0 }; return defstr; } bool ON_OBSOLETE_V5_DimRadial::CreateFromV2( const ON_OBSOLETE_V2_Annotation& v2_ann, const ON_3dmAnnotationSettings& settings, int dimstyle_index ) { bool rc = false; if( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius == v2_ann.m_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter == v2_ann.m_type ) { const ON_SimpleArray& points = v2_ann.Points(); if ( points.Count() >= 4 ) { m_points.Reserve(4); m_points.SetCount(0); m_points.Append(4,points.Array()); m_plane = v2_ann.m_plane; m_plane.UpdateEquation(); SetTextValue(static_cast< const wchar_t* >(v2_ann.UserText())); SetTextFormula(0); m_userpositionedtext = false; m_type = v2_ann.Type(); m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine; SetV5_3dmArchiveDimStyleIndex(dimstyle_index); ON_2dVector v = m_points[0]; if ( !v.IsZero() ) { m_plane.origin = m_plane.PointAt(v.x,v.y); m_plane.UpdateEquation(); v = -v; m_points[0].Set(0.0,0.0); m_points[1] += v; m_points[2] += v; m_points[3] += v; } rc = true; } } return rc; } //----- ON_AngularDimension2Extra ----------------------------------------- // Additions to ON_OBSOLETE_V5_DimAngular class class ON_AngularDimension2Extra : public ON_UserData { ON_OBJECT_DECLARE(ON_AngularDimension2Extra); public: static ON_AngularDimension2Extra* AngularDimensionExtra(ON_OBSOLETE_V5_DimAngular* pDim/*, bool bCreate*/); static const ON_AngularDimension2Extra* AngularDimensionExtra(const ON_OBSOLETE_V5_DimAngular* pDim/*, bool bCreate*/); ON_AngularDimension2Extra(); ~ON_AngularDimension2Extra(); // override virtual ON_Object::Dump function void Dump( ON_TextLog& text_log ) const override; // override virtual ON_Object::SizeOf function unsigned int SizeOf() const override; // override virtual ON_Object::Write function bool Write(ON_BinaryArchive& binary_archive) const override; // override virtual ON_Object::Read function bool Read(ON_BinaryArchive& binary_archive) override; // override virtual ON_UserData::GetDescription function bool GetDescription( ON_wString& description ) override; // override virtual ON_UserData::Archive function bool Archive() const override; // Scale all of the length values void Scale( double scale); // double DimpointOffset(int index) const; void SetDimpointOffset(int index, double offset); // offsets from apex of dimension to point from which extension lines start // if these are < 0.0, they are ignored // Extension lines are drawn from theses points to the Arrow tip points // subject to dimexe & dimexo & dimse1 & dimse2 double m_dimpoint_offset[2]; }; ON_OBJECT_IMPLEMENT(ON_AngularDimension2Extra,ON_UserData,"A68B151F-C778-4a6e-BCB4-23DDD1835677"); ON_AngularDimension2Extra* ON_AngularDimension2Extra::AngularDimensionExtra(ON_OBSOLETE_V5_DimAngular* pDim) { ON_AngularDimension2Extra* pExtra = 0; if(pDim) { pExtra = ON_AngularDimension2Extra::Cast(pDim->GetUserData(ON_CLASS_ID(ON_AngularDimension2Extra))); if(pExtra == 0) { pExtra = new ON_AngularDimension2Extra; if( pExtra) { if(!pDim->AttachUserData(pExtra)) { delete pExtra; pExtra = 0; } } } } return pExtra; } const ON_AngularDimension2Extra* ON_AngularDimension2Extra::AngularDimensionExtra(const ON_OBSOLETE_V5_DimAngular* pDim) { return AngularDimensionExtra((ON_OBSOLETE_V5_DimAngular*)pDim); } ON_AngularDimension2Extra::ON_AngularDimension2Extra() { m_userdata_uuid = ON_CLASS_ID(ON_AngularDimension2Extra); m_application_uuid = ON_opennurbs5_id; // opennurbs.dll reads/writes this userdata // The id must be the version 5 id because // V6 SaveAs V5 needs to work, but SaveAs // V4 should not write this userdata. m_userdata_copycount = 1; m_dimpoint_offset[0] = 0; m_dimpoint_offset[1] = 0; } ON_AngularDimension2Extra::~ON_AngularDimension2Extra() { } void ON_AngularDimension2Extra::Dump( ON_TextLog& text_log ) const { // do nothing } unsigned int ON_AngularDimension2Extra::SizeOf() const { unsigned int sz = ON_UserData::SizeOf(); sz += sizeof(*this) - sizeof(ON_UserData); return sz; } bool ON_AngularDimension2Extra::Write(ON_BinaryArchive& archive) const { int major_version = 1; int minor_version = 0; bool rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,major_version,minor_version); if(rc) rc = archive.WriteDouble(m_dimpoint_offset[0]); if(rc) rc = archive.WriteDouble(m_dimpoint_offset[1]); if(!archive.EndWrite3dmChunk()) rc = false; return rc; } bool ON_AngularDimension2Extra::Read(ON_BinaryArchive& archive) { int major_version = 1; int minor_version = 0; bool rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if(major_version != 1) rc = false; if(rc) rc = archive.ReadDouble(&m_dimpoint_offset[0]); if(rc) rc = archive.ReadDouble(&m_dimpoint_offset[1]); if ( !archive.EndRead3dmChunk() ) rc = false; return rc; } bool ON_AngularDimension2Extra::GetDescription( ON_wString& description) { description = L"Userdata extension of ON_OBSOLETE_V5_DimAngular"; return true; } bool ON_AngularDimension2Extra::Archive() const { // true to write to file return true; } void ON_AngularDimension2Extra::Scale(double scale) { if( ON_IsValid(scale) && scale > ON_SQRT_EPSILON) { m_dimpoint_offset[0] *= scale; m_dimpoint_offset[1] *= scale; } } double ON_AngularDimension2Extra::DimpointOffset(int index) const { if(index == 0) return m_dimpoint_offset[0]; if(index == 1) return m_dimpoint_offset[1]; return -1; } void ON_AngularDimension2Extra::SetDimpointOffset(int index, double offset) { if(index >= 0 && index <= 1) m_dimpoint_offset[index] = offset; } //----- ON_OBSOLETE_V5_DimAngular ----------------------------------------- ON_OBSOLETE_V5_DimAngular::ON_OBSOLETE_V5_DimAngular() : m_angle(0.0) , m_radius(1.0) { m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular; m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine; SetTextValue(DefaultText()); SetTextFormula(0); m_points.Reserve(ON_OBSOLETE_V5_DimAngular::dim_pt_count); m_points.SetCount(ON_OBSOLETE_V5_DimAngular::dim_pt_count); m_points.Zero(); } ON_OBSOLETE_V5_DimAngular* ON_OBSOLETE_V5_DimAngular::CreateFromV2AngularDimension( const class ON_OBSOLETE_V2_DimAngular& V2_angular_dimension, const class ON_3dmAnnotationContext* annotation_context, ON_OBSOLETE_V5_DimAngular* destination ) { ON_OBSOLETE_V5_DimAngular* V5_angular_dimension = (nullptr != destination) ? destination : new ON_OBSOLETE_V5_DimAngular(); V5_angular_dimension->Internal_InitializeFromV2Annotation(V2_angular_dimension,annotation_context); ON_2dVector v0 // point on first line = (V2_angular_dimension.m_points.Count() >= 2 && V2_angular_dimension.m_points[0].IsValid()) ? (V2_angular_dimension.m_points[0] - ON_2dPoint::Origin) : ON_2dVector::ZeroVector; ON_2dVector v1 // point on second line = (V2_angular_dimension.m_points.Count() >= 2 && V2_angular_dimension.m_points[1].IsValid()) ? (V2_angular_dimension.m_points[1] - ON_2dPoint::Origin) : ON_2dVector::ZeroVector; ON_2dPoint tp // point on second line = (V2_angular_dimension.m_points.Count() >= 3 && V2_angular_dimension.m_points[2].IsValid()) ? V2_angular_dimension.m_points[2] : ON_2dPoint::UnsetPoint; double angle = V2_angular_dimension.Radius(); double radius = V2_angular_dimension.Angle(); bool bUserPositionedText = (v0.IsNotZero() && v1.IsNotZero() && V5_angular_dimension->m_userpositionedtext && tp.IsValid()); V5_angular_dimension->m_userpositionedtext = bUserPositionedText; if (v0.IsNotZero() && v1.IsNotZero()) { ON_Plane plane = V5_angular_dimension->m_plane; for (;;) { if (v0.x > 0.0 && 0.0 == v0.y) break; bUserPositionedText = false; const double length0 = v0.Length(); if (!(length0 > 0.0)) break; const ON_3dPoint P0 = plane.PointAt(v0.x, v0.y); if (!P0.IsValid()) break; const ON_3dPoint P1 = plane.PointAt(v1.x, v1.y); if (!P1.IsValid()) break; plane.xaxis = P0 - plane.origin; if (!plane.xaxis.Unitize()) break; plane.yaxis = ON_CrossProduct(plane.zaxis, plane.xaxis); if (!plane.yaxis.Unitize()) break; if (!plane.IsValid()) break; ON_2dVector v = v1; if (!plane.ClosestPointTo(P1, &v.x, &v.y)) break; v0.x = length0; v0.y = 0.0; v1 = v; V5_angular_dimension->m_plane = plane; angle = atan2(v1.y,v1.x); if ( angle < 0.0 ) angle += 2.0*ON_PI; radius = 0.5*(v0.Length() + v1.Length()); break; } } if ( !bUserPositionedText ) { tp.x = radius*cos(0.5*angle); tp.y = radius*sin(0.5*angle); } const ON_2dPoint arcpt( radius*cos(angle/3.0), radius*sin(angle/3.0) ); V5_angular_dimension->m_points.SetCapacity(4); V5_angular_dimension->m_points.SetCount(4); V5_angular_dimension->m_points[0] = tp.IsValid() ? tp : ON_2dPoint::Origin; V5_angular_dimension->m_points[1] = (v0.IsValid() && v0.IsNotZero()) ? ON_2dPoint(v0) : ON_2dPoint::Origin; V5_angular_dimension->m_points[2] = (v1.IsValid() && v1.IsNotZero()) ? ON_2dPoint(v1) : ON_2dPoint::Origin; V5_angular_dimension->m_points[3] = arcpt.IsValid() ? arcpt : ON_2dPoint::Origin; V5_angular_dimension->m_angle = angle; V5_angular_dimension->m_radius = radius; V5_angular_dimension->m_userpositionedtext = bUserPositionedText; return V5_angular_dimension; } bool ON_OBSOLETE_V5_DimAngular::IsValid( ON_TextLog* text_log ) const { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular\n"); } return false; } if ( !ON_OBSOLETE_V5_Annotation::IsValid( text_log )) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - invalid ON_OBSOLETE_V5_Annotation base class.\n"); } return false; } if ( 4 != m_points.Count() ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - m_points.Count() = %d (should be 4)\n", m_points.Count() ); } return false; } if ( !ON_IsValid(m_angle) || m_angle <= 0.0 || m_angle > 2.0*ON_PI ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - bogus m_angle = %g\n",m_angle); } return false; } if ( !ON_IsValid(m_radius) || m_radius <= 0.0 ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - bogus m_radius = %g\n",m_radius); } return false; } if ( 0.0 == m_points[1].x && 0.0 == m_points[1].y ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - angle dim m_points[1] = center (should be on start ray).\n"); } return false; } if ( 0.0 == m_points[2].x && 0.0 == m_points[2].y ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - angle dim m_points[2] = center (should be on end ray).\n"); } return false; } if ( 0.0 == m_points[3].x && 0.0 == m_points[3].y ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - angle dim m_points[3] = center (should be on interior of arc).\n"); } return false; } double a1 = atan2(m_points[1].y, m_points[1].x); double a2 = atan2(m_points[2].y, m_points[2].x); double a3 = atan2(m_points[3].y, m_points[3].x); if ( a1 < 0.0 ) a1 += 2.0*ON_PI; while ( a2 <= a1 ) a2 += 2.0*ON_PI; while ( a3 < a1 ) // Oct 23 2009 LW changed from a3 <= a1 to allow point at end of arc rr53634 a3 += 2.0*ON_PI; if ( fabs(m_angle - (a2-a1)) > ON_ZERO_TOLERANCE + m_angle*ON_SQRT_EPSILON ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - m_angle = %g != %g = (end angle - start angle)\n",m_angle,a2-a1); } return false; } double r = ON_2dVector(m_points[3]).Length(); if ( fabs(r - m_radius) > ON_ZERO_TOLERANCE + m_radius*ON_SQRT_EPSILON ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - m_radius = %g != %g = |m_point[3])|\n",m_radius,r); } return false; } if ( a3 > a2 ) // Oct 23 2009 LW changed from a3 >= a2 to allow point at end of arc rr53634 { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimAngular - angle dim m_points[3] = not on arc interior.\n"); } return false; } return true; } bool ON_OBSOLETE_V5_DimAngular::GetBBox( double* boxmin, double* boxmax, bool bGrowBox ) const { ON_BoundingBox bbox; if ( bGrowBox ) { bbox.m_min.x = boxmin[0]; bbox.m_min.y = boxmin[1]; bbox.m_min.z = boxmin[2]; bbox.m_max.x = boxmax[0]; bbox.m_max.y = boxmax[1]; bbox.m_max.z = boxmax[2]; if ( !bbox.IsValid() ) { bbox.Destroy(); bGrowBox = false; } } ON_Arc arc; if ( GetArc(arc) ) { if ( arc.GetTightBoundingBox(bbox,bGrowBox?true:false,0) ) bGrowBox = true; } if ( bGrowBox ) { boxmin[0] = bbox.m_min.x; boxmin[1] = bbox.m_min.y; boxmin[2] = bbox.m_min.z; boxmax[0] = bbox.m_max.x; boxmax[1] = bbox.m_max.y; boxmax[2] = bbox.m_max.z; } return bGrowBox; } bool ON_OBSOLETE_V5_DimAngular::GetTightBoundingBox( ON_BoundingBox& tight_bbox, bool bGrowBox, const ON_Xform* xform ) const { ON_Arc arc; if ( GetArc(arc) ) { if ( arc.GetTightBoundingBox(tight_bbox,bGrowBox,xform) ) bGrowBox = true; } else if ( bGrowBox && !tight_bbox.IsValid() ) { tight_bbox.Destroy(); bGrowBox = false; } return (0!=bGrowBox); } ON_2dPoint ON_OBSOLETE_V5_DimAngular::Dim2dPoint( int point_index ) const { ON_2dPoint p2; if ( m_points.Count() < dim_pt_count || point_index < 0 ) { p2.x = p2.y = ON_UNSET_VALUE; } else { if ( text_pivot_pt == point_index ) { point_index = m_userpositionedtext ? userpositionedtext_pt_index : arcmid_pt; } if ( point_index < dim_pt_count ) { p2 = m_points[point_index]; } else { switch(point_index) { case arcstart_pt: p2.x = m_radius; p2.y = 0.0; break; case arcend_pt: p2.x = m_radius*cos(m_angle); p2.y = m_radius*sin(m_angle); break; case arccenter_pt: p2.x = 0.0; p2.y = 0.0; break; case arcmid_pt: p2.x = m_radius*cos(0.5*m_angle); p2.y = m_radius*sin(0.5*m_angle); break; case extension0_pt: { p2 = m_points[start_pt_index]; double dp0 = DimpointOffset(0); if(dp0 >= 0) { ON_2dVector v2 = (ON_2dVector)p2; v2.Unitize(); p2 = (ON_2dPoint)v2 * dp0; } } break; case extension1_pt: { p2 = m_points[end_pt_index]; double dp1 = DimpointOffset(1); if(dp1 >= 0) { ON_2dVector v2 = (ON_2dVector)p2; v2.Unitize(); p2 = (ON_2dPoint)v2 * dp1; } } break; default: p2.x = p2.y = ON_UNSET_VALUE; break; } } } return p2; } ON_3dPoint ON_OBSOLETE_V5_DimAngular::Dim3dPoint( int point_index ) const { ON_2dPoint p2 = Dim2dPoint(point_index); if (ON_UNSET_VALUE == p2.x) return ON_3dPoint::UnsetPoint; ON_3dPoint p = m_plane.PointAt(p2.x, p2.y); return p; //return (ON_UNSET_VALUE == p2.x) ? ON_3dPoint::UnsetPoint : m_plane.PointAt(p2.x,p2.y); } bool ON_OBSOLETE_V5_DimAngular::Write( ON_BinaryArchive& file ) const { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_DimLinear // V4 did not have a ON_OBSOLETE_V5_DimLinear::Write and simply called // ON_OBSOLETE_V5_Annotation::Write. bool rc = false; bool bInChunk = (file.Archive3dmVersion() >= 5); if ( bInChunk ) { rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Write(file)?true:false; if (!rc) break; rc = file.WriteDouble( m_angle); if (!rc) break; rc = file.WriteDouble( m_radius); if (!rc) break; if ( !bInChunk ) break; // to write new V5 fields, increment the minor // version number and write them below break; } if ( bInChunk ) { if (!file.EndWrite3dmChunk()) rc = false; } return rc; } bool ON_OBSOLETE_V5_DimAngular::Read( ON_BinaryArchive& file ) { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_DimAngular int major_version = 0; int minor_version = 0; bool rc = false; bool bInChunk = (file.Archive3dmVersion() >= 5 && file.ArchiveOpenNURBSVersion() >= 200710180); if ( bInChunk ) { rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Read(file)?true:false; if (!rc) break; rc = file.ReadDouble( &m_angle); if (!rc) break; rc = file.ReadDouble( &m_radius); if (!rc) break; if ( !bInChunk || minor_version <= 0 ) break; // Code to read any new ON_OBSOLETE_V5_DimAngular fields will // go here. break; } if ( bInChunk ) { // To read new ON_OBSOLETE_V5_DimAngular specific additions, // examine the minor version number and read the information // here. Please ask Dale Lear for help. if ( !file.EndRead3dmChunk() ) rc = false; } return rc; } static bool VectorAngle( const ON_2dVector& v, double& angle) { if( v.IsTiny()) return false; angle = atan2( v.y, v.x); if( angle < 0.0) angle += 2.0 * ON_PI; if( angle > 2.0 * ON_PI) angle -= 2.0 * ON_PI; return true; } bool ON_OBSOLETE_V5_DimAngular::CreateFromArc( const ON_Arc& arc ) { // June 9, 2010 - Lowell - Changed to call CreateFromPoints() bool rc = arc.IsValid(); if (rc) { ON_3dPoint C = arc.Center(); ON_3dPoint S = arc.StartPoint(); ON_3dPoint E = arc.EndPoint(); ON_3dPoint M = arc.MidPoint(); ON_3dVector N = arc.Plane().zaxis; rc = CreateFromPoints(C, S, E, M, N); } return rc; } bool ON_OBSOLETE_V5_DimAngular::GetArc( ON_Arc& arc ) const { bool rc = false; // Jan 25, 2007 - changed min radius from >0 to >ON_SQRT_EPSILON // to avoid domain problems trying to use very small arcs later if ( ON_IsValid(m_radius) && m_radius > ON_SQRT_EPSILON && ON_IsValid(m_angle) && m_angle > 0.0 && m_angle <= 2.0*ON_PI && m_plane.origin.IsValid() && m_plane.xaxis.IsValid() && m_plane.yaxis.IsValid() && m_plane.zaxis.IsValid() && fabs( m_plane.zaxis.Length() - 1.0 ) <= ON_SQRT_EPSILON && 4 == m_points.Count() ) { ON_3dVector X = m_plane.PointAt( m_points[start_pt_index].x, m_points[start_pt_index].y ) - m_plane.origin; if ( fabs(X.Length()-1.0) <= ON_SQRT_EPSILON || X.Unitize() ) { if ( fabs(X*m_plane.zaxis) <= ON_SQRT_EPSILON ) { ON_3dVector Y = ON_CrossProduct( m_plane.zaxis, X ); if ( fabs(Y.Length()-1.0) <= ON_SQRT_EPSILON || Y.Unitize() ) { arc.plane = m_plane; arc.plane.xaxis = X; arc.plane.yaxis = Y; arc.plane.UpdateEquation(); arc.SetAngleIntervalRadians( ON_Interval(0.0,m_angle) ); arc.radius = m_radius; rc = true; } } } } return rc; } bool ON_OBSOLETE_V5_DimAngular::GetExtensionLines(ON_Line extensions[2]) const { bool rc = false; if ( ON_IsValid(m_radius) && m_radius > ON_SQRT_EPSILON && ON_IsValid(m_angle) && m_angle > 0.0 && m_angle <= 2.0*ON_PI && m_plane.origin.IsValid() && m_plane.xaxis.IsValid() && m_plane.yaxis.IsValid() && m_plane.zaxis.IsValid() && fabs( m_plane.zaxis.Length() - 1.0 ) <= ON_SQRT_EPSILON && 4 == m_points.Count() ) { const ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this); if(pDE != 0) { double exoffset0 = pDE->DimpointOffset(0); double exoffset1 = pDE->DimpointOffset(1); ON_3dPoint e00, e01, e10, e11; e00 = m_plane.PointAt(m_points[start_pt_index].x, m_points[start_pt_index].y); e10 = m_plane.PointAt(m_points[end_pt_index].x, m_points[end_pt_index].y); ON_3dVector X = e00 - m_plane.origin; ON_3dVector Y = e10 - m_plane.origin; if((fabs(X.Length()-1.0) <= ON_SQRT_EPSILON || X.Unitize()) && (fabs(Y.Length()-1.0) <= ON_SQRT_EPSILON || Y.Unitize())) { if((fabs(X*m_plane.zaxis) <= ON_SQRT_EPSILON) && (fabs(Y*m_plane.zaxis) <= ON_SQRT_EPSILON)) { e00 = m_plane.origin + X * exoffset0; e10 = m_plane.origin + Y * exoffset1; e01 = m_plane.origin + X * m_radius; e11 = m_plane.origin + Y * m_radius; extensions[0].from = e00; extensions[0].to = e01; extensions[1].from = e10; extensions[1].to = e11; rc = true; } } } } return rc; } bool ON_OBSOLETE_V5_DimAngular::CreateFromPoints( const ON_3dPoint& pc, const ON_3dPoint& p0in, const ON_3dPoint& p1in, ON_3dPoint& arcpt, ON_3dVector& Normal) { ON_3dPoint p0, p1; p0 = p0in; p1 = p1in; ON_Plane plane( pc, Normal); ON_2dPoint pa, pp0, pp1; if( !plane.ClosestPointTo( p0, &pp0.x, &pp0.y)) return false; // rotate so that p0 is on x-axis ON_2dVector v0( pp0); v0.Unitize(); if ( v0.IsValid() && v0.IsNotZero() ) plane.Rotate( v0.y, v0.x, plane.Normal()); if( !plane.ClosestPointTo( p0, &pp0.x, &pp0.y)) return false; if( !plane.ClosestPointTo( arcpt, &pa.x, &pa.y)) return false; if( !plane.ClosestPointTo( p1, &pp1.x, &pp1.y)) return false; double a1 = ON_DBL_QNAN; double aa = ON_DBL_QNAN; if( !VectorAngle( ON_2dVector( pp1), a1) || !VectorAngle( ON_2dVector( pa), aa)) return false; if( aa > a1) // the angle is really the bigger one ( > 180) { // rotate so that p0 is on x-axis v0.Set( pp1.x, pp1.y); v0.Unitize(); plane.Rotate( v0.y, v0.x, plane.Normal()); if( !plane.ClosestPointTo( arcpt, &pa.x, &pa.y)) return false; if( !plane.ClosestPointTo( p1, &pp0.x, &pp0.y)) return false; if( !plane.ClosestPointTo( p0, &pp1.x, &pp1.y)) return false; } VectorAngle( ON_2dVector( pp1), a1); SetAngle( a1); SetRadius( ON_2dVector( pa).Length()); ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this); if(pDE != 0) { double os = ((ON_2dVector)pp0).Length(); pDE->SetDimpointOffset(0, os); os = ((ON_2dVector)pp1).Length(); pDE->SetDimpointOffset(1, os); } ReservePoints( 4); SetPlane( plane); SetPoint( 1, pp0); SetPoint( 2, pp1); SetPoint( 3, pa); return true; } void ON_OBSOLETE_V5_DimAngular::SetAngle( double angle) { m_angle = angle; } double ON_OBSOLETE_V5_DimAngular::Angle() const { return m_angle; } void ON_OBSOLETE_V5_DimAngular::SetRadius( double radius) { m_radius = radius; } double ON_OBSOLETE_V5_DimAngular::Radius() const { return m_radius; } double ON_OBSOLETE_V5_DimAngular::NumericValue() const { // This returns degrees - if we get another angular unit system, add it return (m_angle*180.0/ON_PI); } int ON_OBSOLETE_V5_DimAngular::StyleIndex() const { return ON_OBSOLETE_V5_Annotation::V5_3dmArchiveDimStyleIndex(); } void ON_OBSOLETE_V5_DimAngular::SetStyleIndex( int i) { ON_OBSOLETE_V5_Annotation::SetV5_3dmArchiveDimStyleIndex( i); } const wchar_t* ON_OBSOLETE_V5_DimAngular::DefaultText() { return L"<>"; // Aug 31, 2009 - Lowell } static void OrientRectHelper( ON_2dVector corners[4] ) { double twice_area = 0.0; ON_2dVector p0, p1; int i; p1 = corners[3]; for ( i = 0; i < 4; i++ ) { p0 = p1; p1 = corners[i]; twice_area += (p0.x-p1.x)*(p0.y+p1.y); } if ( twice_area < 0.0 ) { p1 = corners[1]; corners[1] = corners[3]; corners[3] = p1; } } int ON_OBSOLETE_V5_DimAngular::GetDimensionArcSegments( ON_OBSOLETE_V5_RECT gdi_text_rect, int gdi_height_of_I, ON_Xform gdi_to_world, const ON_DimStyle& dimstyle, double dimscale, const ON_Viewport* vp, double a[6], bool& bInside ) const { int rc = 0; a[0] = 0.0; a[1] = 0.0; if ( m_angle <= 0.0 || !ON_IsValid(m_angle) ) return 0; a[1] = m_angle; if ( m_radius <= 0.0 || !ON_IsValid(m_radius) || m_angle >= 2.0*ON_PI ) return 0; if ( 0 == gdi_height_of_I ) { // Default to height of Ariel 'I' (this code still works if ON_Font::Constants::AnnotationFontCellHeight != 256) gdi_height_of_I = (165*ON_Font::Constants::AnnotationFontCellHeight)/256; } if ( 0.0 == dimscale ) { dimscale = 1.0; } double t; ON_INTERNAL_OBSOLETE::V5_TextDisplayMode textdisplay = ON_INTERNAL_OBSOLETE::V5TextDisplayModeFromV6DimStyle(dimstyle); const double text_height_of_I = dimscale*dimstyle.TextHeight(); const double textgap = dimscale*dimstyle.TextGap(); const double gdi_to_plane_scale = text_height_of_I/gdi_height_of_I; const double textwidth = fabs(gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left)); const double arrowwidth = fabs(dimscale*dimstyle.ArrowSize()); const double tailwidth = 0.5*arrowwidth; const double dimextension = fabs(dimscale*dimstyle.DimExtension()); const double a0 = 0.0; const double a1 = m_angle; double sin_angle = 0.5*dimextension/m_radius; if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0; const double dimextension_angle = 2.0*asin(sin_angle); sin_angle = 0.5*arrowwidth/m_radius; if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0; const double arrowangle = 2.0*asin(sin_angle); sin_angle = 0.5*tailwidth/m_radius; if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0; const double tailangle = 2.0*asin(sin_angle); // June 7, 2010 - Lowell - Added some special handling for very small dimensions double arrow_angle = arrowangle + tailangle; if(arrow_angle > ON_PI * 0.5) arrow_angle = ON_PI * 0.5; if ( m_radius <= arrowwidth + tailwidth || m_radius*(a1-a0) < 2.0*(arrowwidth) + tailwidth ) { // arc is tiny with respect to arrowhead size - arrowheads have to be "outside" // 2 arc segments, arrowheads outside a[0] = a0; a[1] = a0 - arrow_angle; a[2] = a1 + arrow_angle; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] += dimextension_angle; a[3] -= dimextension_angle; } bInside = false; return 2; } if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine == textdisplay && m_radius <= 0.5*(textwidth + 2.0*textgap)) { // 2 arc segments, arrowheads outside a[0] = a0; a[1] = a0 - arrow_angle; a[2] = a1 + arrow_angle; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] += dimextension_angle; a[3] -= dimextension_angle; } bInside = false; return 2; } sin_angle = 0.5*(textwidth+2.0*textgap)/m_radius; if ( sin_angle > 1.0 ) sin_angle = 1.0; else if (sin_angle < -1.0) sin_angle = -1.0; const double textangle = (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine == textdisplay && !m_userpositionedtext) ? 2.0*asin(sin_angle) : 0.0; if ( (a1-a0) <= 2.0*(arrow_angle) + textangle ) { // 2 arc segments, arrowheads outside a[0] = a0; a[1] = a0 - arrow_angle; a[2] = a1 + arrow_angle; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] += dimextension_angle; a[3] -= dimextension_angle; } bInside = false; return 2; } if ((ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen == textdisplay && vp) || m_userpositionedtext) { // use projected rectangle to clip dimension arc double aa0, aa1, aa, r0, r1, tt[2]; ON_3dPoint P, R, c[2]; ON_2dVector corners[4], N; ON_Line ray; int i,xi, xrc; const ON_Circle circle(ON_xy_plane,1.0); ON_3dVector vp_zaxis = (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen == textdisplay && vp) ? vp->CameraZ() : m_plane.zaxis; // 30 July 2012 - Lowell - Slightly shrink the text gap value // so that text + gap won't intersect the dim line if when text // is moved along the dim line. rr110504 double gdi_gap = fabs(textgap/gdi_to_plane_scale)-12; if(gdi_gap < 0.0) gdi_gap = 0.0; R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[0].x,&corners[0].y); R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.bottom+gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[1].x,&corners[1].y); R.Set(gdi_text_rect.right+gdi_gap,gdi_text_rect.top-gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[2].x,&corners[2].y); R.Set(gdi_text_rect.left-gdi_gap,gdi_text_rect.top-gdi_gap,0.0); ray.from = gdi_to_world*R; ray.to = ray.from + vp_zaxis; P = ( ON_Intersect(ray,m_plane,&t) ) ? ray.PointAt(t) : ray.from; m_plane.ClosestPointTo(P,&corners[3].x,&corners[3].y); // orient projected rect so it is counter-clockwise OrientRectHelper(corners); aa0 = a0; aa1 = a1; P.Set(cos(a0)*m_radius,sin(a0)*m_radius,0.0); R.Set(cos(a1)*m_radius,sin(a1)*m_radius,0.0); for ( i = 0; i < 4; i++ ) { N.x = (corners[i].y-corners[(i+1)%4].y); N.y = (corners[(i+1)%4].x-corners[i].x); if ( !N.Unitize() ) continue; if ( (P.x - corners[i].x)*N.x + (P.y - corners[i].y)*N.y < 0.0 ) { // end point not in text box aa0 = ON_UNSET_VALUE; } if ( (R.x - corners[i].x)*N.x + (R.y - corners[i].y)*N.y < 0.0 ) { // start point not in text box aa1 = ON_UNSET_VALUE; } } if ( ON_UNSET_VALUE == aa0 ) aa0 = aa1; else if ( ON_UNSET_VALUE == aa1 ) aa1 = aa0; r1 = corners[3].Length() - m_radius; ray.to.x = corners[3].x/m_radius; ray.to.y = corners[3].y/m_radius; ray.to.z = ray.from.z = 0.0; for ( i = 0; i < 4; i++ ) { r0 = r1; r1 = corners[i].Length() - m_radius; ray.from = ray.to; ray.to.x = corners[i].x/m_radius; ray.to.y = corners[i].y/m_radius; if ( r0 < 0.0 && r1 < 0.0 ) { continue; // ray is inside circle } if ( r0 > 0.0 && r1 > 0.0 ) { if ( !ray.ClosestPointTo(ON_3dPoint::Origin,&t ) ) continue; R = ray.PointAt(t); if ( R.x*R.x + R.y*R.y >= 1.0 ) continue; // ray is outside circle } xrc = 0; if ( 0.0 == r0 ) tt[xrc++] = 0.0; if ( 0.0 == r1 ) tt[xrc++] = 1.0; if ( 0 == xrc ) xrc = ON_Intersect(ray,circle,&tt[0],c[0],&tt[1],c[1]); if ( xrc < 1 || xrc > 2 ) continue; // ray does not intersect circle; for ( xi = 0; xi < xrc; xi++ ) { if ( tt[xi] < 0.0 || tt[xi] > 1.0 ) continue; // intersection point not on segment P = ray.PointAt(tt[xi]); if ( 0.0 == P.x && 0.0 == P.y ) continue; // bogus aa = atan2(P.y,P.x); if ( aa < a0 ) aa += 2.0*ON_PI; else if ( aa > a1 ) aa -= 2.0*ON_PI; if ( aa < a0 || aa > a1 ) { continue; } if ( ON_UNSET_VALUE == aa0 ) aa0 = aa1 = aa; else if ( aa < aa0 ) aa0 = aa; else if ( aa > aa1 ) aa1 = aa; } } if ( ON_UNSET_VALUE != aa0 && ON_UNSET_VALUE != aa1 && a0 <= aa0 && aa0 < aa1 && aa1 <= a1 ) { t = arrow_angle; if ( aa0 < a0+t && aa1 > a1-t ) { // text box hits both arrowheads // 2 arc segments, arrowheads outside a[0] = a0; a[1] = a0 - arrow_angle; a[2] = a1 + arrow_angle; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] += dimextension_angle; a[3] -= dimextension_angle; } bInside = false; rc = 2; } else { if ( aa0 < a0+t ) aa0 = a0+t; if ( aa1 > a1-t ) aa1 = a1-t; if ( a0 < aa0 && aa0 < aa1 && aa1 < a1 ) { // clip arc to text rectangle // 2 arc segments, arrowheads inside a[0] = a0; a[1] = aa0; a[2] = aa1; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] -= dimextension_angle; a[3] += dimextension_angle; } bInside = true; rc = 2; } else { // nasty case - don't bother clipping // 1 segment, arrows inside a[0] = a0; a[1] = a1; a[2] = a0; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] -= dimextension_angle; a[1] += dimextension_angle; } bInside = true; rc = 1; } } } else { // 1 segment, arrows inside a[0] = a0; a[1] = a1; a[2] = a0; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] -= dimextension_angle; a[1] += dimextension_angle; } bInside = true; rc = 1; } } else if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine == textdisplay || m_userpositionedtext) { // 1 segment, arrows inside a[0] = a0; a[1] = a1; a[2] = a0; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] -= dimextension_angle; a[1] += dimextension_angle; } bInside = true; rc = 1; } else if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine == textdisplay) { // 2 segments, arrows inside t = 0.5*((a1-a0) - textangle); a[0] = a0; a[1] = a0+t; a[2] = a1-t; a[3] = a1; a[4] = a0; a[5] = a1; if( dimextension_angle != 0.0) { a[0] -= dimextension_angle; a[3] += dimextension_angle; } bInside = true; rc = 2; } return rc; } double ON_OBSOLETE_V5_DimAngular::DimpointOffset(int index) const { const ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this); if(pDE != 0) return pDE->DimpointOffset(index); return -1.0; } void ON_OBSOLETE_V5_DimAngular::SetDimpointOffset(int index, double offset) { ON_AngularDimension2Extra* pDE = ON_AngularDimension2Extra::AngularDimensionExtra(this); if(pDE != 0) pDE->SetDimpointOffset(index, offset); } //----- ON_OBSOLETE_V5_DimOrdinate ----------------------------------------- ON_OBSOLETE_V5_DimOrdinate::ON_OBSOLETE_V5_DimOrdinate() { m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate; SetTextValue(DefaultText()); SetTextFormula(0); m_direction = -1; // undetermined direction m_points.Reserve(ON_OBSOLETE_V5_DimOrdinate::dim_pt_count); m_points.SetCount(ON_OBSOLETE_V5_DimOrdinate::dim_pt_count); m_points.Zero(); m_kink_offset_0 = ON_UNSET_VALUE; m_kink_offset_1 = ON_UNSET_VALUE; } ON_OBSOLETE_V5_DimOrdinate::~ON_OBSOLETE_V5_DimOrdinate() { } bool ON_OBSOLETE_V5_DimOrdinate::Transform( const ON_Xform& xform ) { bool rc = xform.IsIdentity(); if ( !rc) { return ON_OBSOLETE_V5_Annotation::Transform(xform); } return rc; } ON_2dPoint ON_OBSOLETE_V5_DimOrdinate::Dim2dPoint( int point_index, double default_offset) const { ON_2dPoint p2( ON_UNSET_VALUE, ON_UNSET_VALUE); int dir = m_direction; if( dir == -1 && ( point_index == offset_pt_0 || point_index == offset_pt_1)) { if( fabs( m_points[definition_pt_index].y - m_points[leader_end_pt_index].y) > fabs( m_points[definition_pt_index].x - m_points[leader_end_pt_index].x)) dir = 0; else dir = 1; } if( point_index >= 0 && point_index < dim_pt_count && m_points.Count() == dim_pt_count) { p2 = m_points[point_index]; } else if( point_index == text_pivot_pt) { // ON_3dPoint::UnsetPoint } else if( point_index == offset_pt_0) { double offset; if( m_kink_offset_0 == ON_UNSET_VALUE) offset = default_offset; else offset = m_kink_offset_0; if( dir == x) { p2 = m_points[leader_end_pt_index]; if( p2.y > m_points[definition_pt_index].y) p2.y -= offset; else p2.y += offset; } else if( dir == y) { p2 = m_points[leader_end_pt_index]; if( p2.x > m_points[definition_pt_index].x) p2.x -= offset; else p2.x += offset; } } else if( point_index == offset_pt_1) { double offset0; if( m_kink_offset_0 == ON_UNSET_VALUE) offset0 = default_offset; else offset0 = m_kink_offset_0; double offset1; if( m_kink_offset_1 == ON_UNSET_VALUE) offset1 = default_offset; else offset1 = m_kink_offset_1; if( dir == x) { p2.x = m_points[definition_pt_index].x; if( m_points[leader_end_pt_index].y > m_points[definition_pt_index].y) p2.y = m_points[leader_end_pt_index].y - offset0 - offset1; else p2.y = m_points[leader_end_pt_index].y + offset0 + offset1; } else if( dir == y) { p2.y = m_points[definition_pt_index].y; if( m_points[leader_end_pt_index].x > m_points[definition_pt_index].x) p2.x = m_points[leader_end_pt_index].x - offset0 - offset1; else p2.x = m_points[leader_end_pt_index].x + offset0 + offset1; } } return p2; } ON_3dPoint ON_OBSOLETE_V5_DimOrdinate::Dim3dPoint( int point_index, double default_offset) const { ON_2dPoint p2 = Dim2dPoint(point_index, default_offset); return (ON_UNSET_VALUE == p2.x) ? ON_3dPoint::UnsetPoint : m_plane.PointAt(p2.x,p2.y); } bool ON_OBSOLETE_V5_DimOrdinate::IsValid( ON_TextLog* text_log) const { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimOrdinate - m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate.\n"); } return false; } if ( !ON_OBSOLETE_V5_Annotation::IsValid( text_log )) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimOrdinate - invalid ON_OBSOLETE_V5_Annotation base class.\n"); } return false; } if ( m_points.Count() != 2 ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_DimOrdinate - m_points.Count() = %d (should be 2).\n",m_points.Count()); } return false; } return true; } bool ON_OBSOLETE_V5_DimOrdinate::Write( ON_BinaryArchive& file ) const { // put the entire ON_OBSOLETE_V5_DimOrdinate in a chunk so we can // add fields without breaking the file IO for old product. bool rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,1); if (rc) { rc = file.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if (rc) { // As of 18 October 2007, the following comment is out of date. // But, we still need to write this "extra" chunk so we don't // break V4 file writing. // // The output of ON_OBSOLETE_V5_Annotation::Write must be wrapped // in an additional chunk because it does not put // itself in a chunk. If you don't put it in a chunk, // the versioning in the ON_OBSOLETE_V5_Annotation::Write is useless and // will cause serious IO bugs if fields are ever added. rc = ON_OBSOLETE_V5_Annotation::Write( file) ? true : false; if (!file.EndWrite3dmChunk() ) rc = false; } if (rc) rc = file.WriteInt( m_direction); // kink offsets, ver 1.1 added 2-4-06 if (rc) rc = file.WriteDouble( m_kink_offset_0); if (rc) rc = file.WriteDouble( m_kink_offset_1); // end of ON_OBSOLETE_V5_DimOrdinate chunk if (!file.EndWrite3dmChunk() ) rc = false; } return rc; } bool ON_OBSOLETE_V5_DimOrdinate::Read( ON_BinaryArchive& file ) { int major_version=0, minor_version=0; bool rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if (rc) { if ( 1 != major_version ) { rc = false; } else { int submajor_version=0, subminor_version=0; // subchunk wraps ON_OBSOLETE_V5_Annotation field so this // function won't break if ON_OBSOLETE_V5_Annotation changes. rc = file.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&submajor_version,&subminor_version); if (rc) { if ( 1 != submajor_version ) rc = false; else { rc = ON_OBSOLETE_V5_Annotation::Read( file) ? true : false; } if ( !file.EndRead3dmChunk() ) rc = false; } if( rc) rc = file.ReadInt( &m_direction); if( minor_version > 0) { if( rc) rc = file.ReadDouble( &m_kink_offset_0); if( rc) rc = file.ReadDouble( &m_kink_offset_1); } } if (!file.EndRead3dmChunk()) rc = false; } return rc; } double ON_OBSOLETE_V5_DimOrdinate::NumericValue() const { if( m_direction == 0) return m_points[1].x - m_points[0].x; else return m_points[1].y - m_points[0].y; } int ON_OBSOLETE_V5_DimOrdinate::StyleIndex() const { return ON_OBSOLETE_V5_Annotation::V5_3dmArchiveDimStyleIndex(); } void ON_OBSOLETE_V5_DimOrdinate::SetStyleIndex( int i) { ON_OBSOLETE_V5_Annotation::SetV5_3dmArchiveDimStyleIndex( i); } bool ON_OBSOLETE_V5_DimOrdinate::GetBBox( double* boxmin, double* boxmax, bool bGrowBox ) const { ON_BoundingBox bbox; if ( bGrowBox ) { bbox.m_min.x = boxmin[0]; bbox.m_min.y = boxmin[1]; bbox.m_min.z = boxmin[2]; bbox.m_max.x = boxmax[0]; bbox.m_max.y = boxmax[1]; bbox.m_max.z = boxmax[2]; if ( !bbox.IsValid() ) { bbox.Destroy(); bGrowBox = false; } } if( m_points.Count() == 2) { ON_3dPointArray P( 2); P.Append( m_plane.PointAt( m_points[0].x, m_points[0].y)); P.Append( m_plane.PointAt( m_points[1].x, m_points[1].y)); bGrowBox = P.GetBBox(&bbox.m_min.x, &bbox.m_max.x, bGrowBox); } if ( bGrowBox ) { boxmin[0] = bbox.m_min.x; boxmin[1] = bbox.m_min.y; boxmin[2] = bbox.m_min.z; boxmax[0] = bbox.m_max.x; boxmax[1] = bbox.m_max.y; boxmax[2] = bbox.m_max.z; } return bGrowBox; } bool ON_OBSOLETE_V5_DimOrdinate::GetTightBoundingBox( ON_BoundingBox& tight_bbox, bool bGrowBox, const ON_Xform* xform) const { if( m_points.Count() == 2) { ON_3dPointArray P(2); P.Append( m_plane.PointAt( m_points[0].x, m_points[0].y)); P.Append( m_plane.PointAt( m_points[1].x, m_points[1].y)); if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform)) bGrowBox = true; } else if( bGrowBox && !tight_bbox.IsValid()) { tight_bbox.Destroy(); bGrowBox = false; } return( 0 != bGrowBox); } int ON_OBSOLETE_V5_DimOrdinate::ImpliedDirection() const { int direction = -1; const ON_2dPoint& p0 = m_points[definition_pt_index]; const ON_2dPoint& p1 = m_points[leader_end_pt_index]; if( fabs( p1.x - p0.x) <= fabs( p1.y - p0.y)) direction = 0; // measures along x axis else direction = 1; // measures along y axis return direction; } int ON_OBSOLETE_V5_DimOrdinate::Direction() const { return m_direction; } void ON_OBSOLETE_V5_DimOrdinate::SetDirection( int direction) { m_direction = direction; } const wchar_t* ON_OBSOLETE_V5_DimOrdinate::DefaultText() { return L"<>"; } double ON_OBSOLETE_V5_DimOrdinate::KinkOffset( int index) const { if( index == 0) return m_kink_offset_0; else if( index == 1) return m_kink_offset_1; else return ON_UNSET_VALUE; } void ON_OBSOLETE_V5_DimOrdinate::SetKinkOffset( int index, double offset) { if( index == 0) m_kink_offset_0 = offset; else if( index == 1) m_kink_offset_1 = offset; } void ON_OBSOLETE_V5_DimOrdinate::CalcKinkPoints( ON_2dPoint p0, ON_2dPoint p1, int direction, double default_offset, ON_2dPoint& k0, ON_2dPoint& k1) const { double offset0 = KinkOffset( 0); double offset1 = KinkOffset( 1); // if these haven't been set by dragging the offset points // use 2*textheight if( offset0 == ON_UNSET_VALUE) offset0 = default_offset; if( offset1 == ON_UNSET_VALUE) offset1 = default_offset; if( p0[1-direction] > p1[1-direction]) { offset0 = -offset0; offset1 = -offset1; } //double d = fabs( p0[1-direction] - p1[1-direction]); if( direction == 0) { //if( d - fabs( offset0) > default_offset) //{ k1.x = p0.x; k1.y = p1.y - offset0 - offset1; //} //else //{ // k1.x = p0.x; // k1.y = p1.y + offset0 - offset1; //} k0.x = p1.x; k0.y = p1.y - offset0; } else { //if( d - fabs( offset0) > default_offset) //{ k1.x = p1.x - offset0 - offset1; k1.y = p0.y; //} //else //{ // k1.x = p1.x + offset0 - offset1; // k1.y = p0.y; //} k0.x = p1.x - offset0; k0.y = p1.y; } } //----- ON_OBSOLETE_V5_TextObject ----------------------------------------------- ON_OBSOLETE_V5_TextObject::ON_OBSOLETE_V5_TextObject() { m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock; m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kNormal; } ON_OBSOLETE_V5_TextObject::~ON_OBSOLETE_V5_TextObject() { } bool ON_OBSOLETE_V5_TextObject::IsValid( ON_TextLog* text_log ) const { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_TextObject - m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock\n"); } return false; } // 05 March 2009 S. Baer // Text blocks with no "printable" characters are considered invalid. Any // character with a value greater than 32 (the value of space) is "printable." int count = m_usertext.Length(); bool bValidText = false; for( int i=0; i L' ' ) { bValidText = true; break; } } // 9 Oct 2010 S. Baer // With the addition of text formulas, the user text can be 0 length if( !bValidText && count<1 ) { const wchar_t* formula = TextFormula(); if( formula && formula[0] ) bValidText = true; } if( !bValidText ) { if( text_log ) { text_log->Print("ON_OBSOLETE_V5_TextObject - m_usertext does not contain printable characters.\n"); } return false; } if ( !ON_OBSOLETE_V5_Annotation::IsValid( text_log )) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_TextObject - invalid ON_OBSOLETE_V5_Annotation base class.\n"); } return false; } if ( 0 != m_points.Count() ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_TextObject - m_points.Count() = %d (should be 0)\n", m_points.Count() ); } return false; } return true; } bool ON_OBSOLETE_V5_TextObject::Write(ON_BinaryArchive& archive) const { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_TextObject // V4 did not have a ON_OBSOLETE_V5_TextObject::Write and simply called // ON_OBSOLETE_V5_Annotation::Write. bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5); if ( bInChunk ) { rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Write(archive)?true:false; if (!rc) break; if ( !bInChunk ) break; // To write new fields, increment minor version number // and write values here. Ask Dale Lear for help. break; } if ( bInChunk ) { if (!archive.EndWrite3dmChunk()) rc = false; } return rc; } bool ON_OBSOLETE_V5_TextObject::Read(ON_BinaryArchive& archive) { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_TextObject int major_version = 0; int minor_version = 0; bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180); if ( bInChunk ) { rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Read(archive)?true:false; if (!rc) break; if ( !bInChunk || minor_version <= 0 ) break; // read future addition here break; } if ( bInChunk ) { // To read new ON_OBSOLETE_V5_TextObject specific additions, // examine the minor version number and read the information // here. Please ask Dale Lear for help. if ( !archive.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_OBSOLETE_V5_TextObject::GetBBox( double* boxmin, double* boxmax, bool bGrowBox ) const { ON_BoundingBox bbox; if ( bGrowBox ) { bbox.m_min.x = boxmin[0]; bbox.m_min.y = boxmin[1]; bbox.m_min.z = boxmin[2]; bbox.m_max.x = boxmax[0]; bbox.m_max.y = boxmax[1]; bbox.m_max.z = boxmax[2]; if ( !bbox.IsValid() ) { bbox.Destroy(); bGrowBox = false; } } if ( 1 == m_points.Count() ) { ON_2dPoint uv = m_points[0]; bbox.Set( m_plane.PointAt(uv.x,uv.y), bGrowBox ); bGrowBox = true; } else if ( 0 == m_points.Count() ) { bbox.Set( m_plane.origin, bGrowBox ); bGrowBox = true; } if ( bGrowBox ) { boxmin[0] = bbox.m_min.x; boxmin[1] = bbox.m_min.y; boxmin[2] = bbox.m_min.z; boxmax[0] = bbox.m_max.x; boxmax[1] = bbox.m_max.y; boxmax[2] = bbox.m_max.z; } return bGrowBox; } bool ON_OBSOLETE_V5_TextObject::GetTightBoundingBox( ON_BoundingBox& tight_bbox, bool bGrowBox, const ON_Xform* xform ) const { if ( 1 == m_points.Count() ) { ON_3dPointArray P(1); P.Append( m_plane.PointAt(m_points[0].x,m_points[0].y) ); if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) ) bGrowBox = true; } else if ( bGrowBox && !tight_bbox.IsValid() ) { tight_bbox.Destroy(); bGrowBox = false; } return (0!=bGrowBox); } bool ON_OBSOLETE_V5_TextObject::Transform( const ON_Xform& xform ) { // Dale Lear - this override fixes RR 11114 by correctly // handling non uniform scaling. bool rc = xform.IsIdentity(); if ( !rc) { ON_Plane xformed_plane = m_plane; rc = xformed_plane.Transform(xform); if (rc) rc = ON_Geometry::Transform(xform)?true:false; if (rc) { ON_3dPoint P0 = xform*m_plane.origin; ON_3dPoint P1 = xform*(m_plane.origin + m_plane.xaxis); double s = P0.DistanceTo(P1); if ( s <= ON_ZERO_TOLERANCE ) { P1 = xform*(m_plane.origin + m_plane.yaxis); s = P0.DistanceTo(P1); } m_plane = xformed_plane; if ( s > ON_ZERO_TOLERANCE && fabs(s-1.0) > ON_SQRT_EPSILON ) { s *= m_textheight; if ( s > ON_SQRT_EPSILON ) m_textheight = s; } } } return rc; } void ON_OBSOLETE_V5_TextObject::SetJustification( unsigned int justification) { m_justification = justification; } unsigned int ON_OBSOLETE_V5_TextObject::Justification() const { return m_justification; } bool ON_OBSOLETE_V5_TextObject::DrawTextMask() const { const ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, false); if(pTE) return pTE->DrawTextMask(); else return false; } void ON_OBSOLETE_V5_TextObject::SetDrawTextMask(bool bDraw) { ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, true); if(pTE) pTE->SetDrawTextMask(bDraw); } int ON_OBSOLETE_V5_TextObject::MaskColorSource() const { const ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, false); if(pTE) return pTE->MaskColorSource(); else return 0; } void ON_OBSOLETE_V5_TextObject::SetMaskColorSource(int source) { ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, true); if(pTE) pTE->SetMaskColorSource(source); } ON_Color ON_OBSOLETE_V5_TextObject::MaskColor() const { const ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, false); if(pTE) return pTE->MaskColor(); else return 0; } void ON_OBSOLETE_V5_TextObject::SetMaskColor(ON_Color color) { ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, true); if(pTE) pTE->SetMaskColor(color); } double ON_OBSOLETE_V5_TextObject::MaskOffsetFactor() const { const ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, false); if(pTE) return pTE->MaskOffsetFactor(); else return 0; } void ON_OBSOLETE_V5_TextObject::SetMaskOffsetFactor(double offset) { ON_OBSOLETE_V5_TextExtra* pTE = ON_OBSOLETE_V5_TextExtra::TextExtension(this, true); if(pTE) pTE->SetMaskOffsetFactor(offset); } bool ON_OBSOLETE_V5_TextObject::AnnotativeScaling() const { return m_annotative_scale; } void ON_OBSOLETE_V5_TextObject::SetAnnotativeScaling(bool b) { m_annotative_scale = b; } //----- ON_OBSOLETE_V5_Leader ------------------------------------------ ON_OBSOLETE_V5_Leader::ON_OBSOLETE_V5_Leader() { m_type = ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader; m_textdisplaymode = ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kInLine; } ON_OBSOLETE_V5_Leader::~ON_OBSOLETE_V5_Leader() { } bool ON_OBSOLETE_V5_Leader::IsValid( ON_TextLog* text_log ) const { if ( m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_Leader - m_type != ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader\n"); } return false; } if ( !ON_OBSOLETE_V5_Annotation::IsValid( text_log )) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_Leader - invalid ON_OBSOLETE_V5_Annotation base class.\n"); } return false; } if ( m_points.Count() < 2 ) { if ( text_log ) { text_log->Print("ON_OBSOLETE_V5_Leader - m_points.Count() = %d (should be >= 2)\n", m_points.Count() ); } return false; } return true; } bool ON_OBSOLETE_V5_Leader::Write(ON_BinaryArchive& archive) const { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_Leader // V4 did not have a ON_OBSOLETE_V5_Leader::Write and simply called // ON_OBSOLETE_V5_Leader::Write. bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5); if ( bInChunk ) { rc = archive.BeginWrite3dmChunk(TCODE_ANONYMOUS_CHUNK,1,0); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Write(archive)?true:false; if (!rc) break; if ( !bInChunk ) break; // To write new fields, increment minor version number // and write values here. Ask Dale Lear for help. break; } if ( bInChunk ) { if (!archive.EndWrite3dmChunk()) rc = false; } return rc; } bool ON_OBSOLETE_V5_Leader::Read(ON_BinaryArchive& archive) { // 18 October 2007 Dale Lear // I added the chunk wrapping so V5 and future versions can // add IO support for information specific to ON_OBSOLETE_V5_Leader int major_version = 0; int minor_version = 0; bool rc = false; bool bInChunk = (archive.Archive3dmVersion() >= 5 && archive.ArchiveOpenNURBSVersion() >= 200710180); if ( bInChunk ) { rc = archive.BeginRead3dmChunk(TCODE_ANONYMOUS_CHUNK,&major_version,&minor_version); if ( !rc ) return false; } else { rc = true; } while(rc) { rc = ON_OBSOLETE_V5_Annotation::Read(archive)?true:false; if (!rc) break; if ( !bInChunk || minor_version <= 0 ) break; // read future addition here break; } if ( bInChunk ) { if ( !archive.EndRead3dmChunk() ) rc = false; } return rc; } bool ON_OBSOLETE_V5_Leader::GetBBox( double* boxmin, double* boxmax, bool bGrowBox ) const { ON_BoundingBox bbox; if ( bGrowBox ) { bbox.m_min.x = boxmin[0]; bbox.m_min.y = boxmin[1]; bbox.m_min.z = boxmin[2]; bbox.m_max.x = boxmax[0]; bbox.m_max.y = boxmax[1]; bbox.m_max.z = boxmax[2]; if ( !bbox.IsValid() ) { bbox.Destroy(); bGrowBox = false; } } const int point_count = m_points.Count(); if ( point_count > 0 ) { ON_3dPointArray P(point_count); int i; for ( i = 0; i < point_count; i++ ) { ON_2dPoint uv = m_points[i]; P.Append( m_plane.PointAt(uv.x,uv.y)); } if ( P.GetBoundingBox(bbox,bGrowBox?true:false) ) bGrowBox = true; } if ( bGrowBox ) { boxmin[0] = bbox.m_min.x; boxmin[1] = bbox.m_min.y; boxmin[2] = bbox.m_min.z; boxmax[0] = bbox.m_max.x; boxmax[1] = bbox.m_max.y; boxmax[2] = bbox.m_max.z; } return bGrowBox; } bool ON_OBSOLETE_V5_Leader::GetTightBoundingBox( ON_BoundingBox& tight_bbox, bool bGrowBox, const ON_Xform* xform ) const { const int point_count = m_points.Count(); if ( point_count >= 2 ) { ON_3dPointArray P(point_count); int i; for ( i = 0; i < point_count; i++ ) { ON_2dPoint uv = m_points[i]; P.Append( m_plane.PointAt(uv.x,uv.y)); } if ( P.GetTightBoundingBox( tight_bbox, bGrowBox, xform ) ) bGrowBox = true; } else if ( bGrowBox && !tight_bbox.IsValid() ) { tight_bbox.Destroy(); bGrowBox = false; } return (0!=bGrowBox); } ON_2dPoint ON_OBSOLETE_V5_Leader::Dim2dPoint( int point_index ) const { ON_2dPoint p2; int point_count = m_points.Count(); if ( point_index < 0 || point_count < 1 ) { p2.x = p2.y = ON_UNSET_VALUE; } else { switch(point_index) { case arrow_pt_index: p2 = m_points[0]; break; case text_pivot_pt: case tail_pt: p2 = *m_points.Last(); break; default: if ( point_index < point_count ) { p2 = m_points[point_index]; } else { p2.x = p2.y = ON_UNSET_VALUE; } break; } } return p2; } ON_3dPoint ON_OBSOLETE_V5_Leader::Dim3dPoint( int point_index ) const { ON_2dPoint p2 = Dim2dPoint(point_index); return (ON_UNSET_VALUE == p2.x) ? ON_3dPoint::UnsetPoint : m_plane.PointAt(p2.x,p2.y); } void ON_OBSOLETE_V5_Leader::AddPoint( const ON_2dPoint& point ) { m_points.Append( point); } bool ON_OBSOLETE_V5_Leader::RemovePoint( int idx ) { bool rc = true; if( idx == -1) // -1 removes the last point { m_points.Remove(); } else if( idx >= 0 && idx < m_points.Count()) { m_points.Remove( idx); } else { rc = false; } return rc; } // April 22, 2010 Lowell - Added to support right justified text on left pointing leader tails rr64292 bool ON_OBSOLETE_V5_Leader::GetTextDirection( ON_2dVector& text_dir ) const { bool rc = false; const int point_count = m_points.Count(); if ( point_count < 2 ) { text_dir.Set(-1.0,0.0); } else { int i; // 20 June 2011 Fixed textdir for leaders with 2 points. rr86801 for(i = point_count-1; i >= 1; i--) { text_dir = m_points[point_count-1] - m_points[i-1]; if(text_dir.Unitize()) { rc = true; break; } text_dir.Set(-1.0,0.0); } } return rc; } bool ON_OBSOLETE_V5_Leader::GetArrowHeadDirection( ON_2dVector& arrowhead_dir ) const { bool rc = false; const int point_count = m_points.Count(); if ( point_count < 2 ) { arrowhead_dir.Set(-1.0,0.0); } else { int i; for ( i = 1; i < point_count; i++ ) { arrowhead_dir = m_points[0] - m_points[i]; if ( arrowhead_dir.Unitize() ) { rc = true; break; } arrowhead_dir.Set(-1.0,0.0); } } return rc; } bool ON_OBSOLETE_V5_Leader::GetArrowHeadTip( ON_2dPoint& arrowhead_tip ) const { bool rc = false; switch( m_points.Count()) { case 0: arrowhead_tip.Set(0.0,0.0); break; case 1: arrowhead_tip = m_points[0]; break; default: arrowhead_tip = m_points[0]; rc = true; break; } return rc; } bool ON_OBSOLETE_V5_DimRadial::GetArrowHeadDirection( ON_2dVector& arrowhead_dir ) const { bool rc = false; if ( m_points.Count() < 4 ) { arrowhead_dir.Set(-1.0,0.0); } else { arrowhead_dir = m_points[1] - m_points[3]; if ( 0 == (rc=arrowhead_dir.Unitize()) ) { arrowhead_dir = m_points[1] - m_points[2]; if ( 0 == (rc=arrowhead_dir.Unitize()) ) { arrowhead_dir = m_points[0] - m_points[1]; rc = arrowhead_dir.Unitize(); } } } return rc; } bool ON_OBSOLETE_V5_DimRadial::GetArrowHeadTip( ON_2dPoint& arrowhead_tip ) const { bool rc = false; if ( m_points.Count() >= 2 ) { arrowhead_tip = m_points[1]; rc = true; } else { arrowhead_tip.Set(0.0,0.0); rc = false; } return rc; } // class ON_TextDot //-------------------------------------------------------------------- ON_TextDot::ON_TextDot() {} ON_TextDot* ON_TextDot::CreateFromV2AnnotationTextDot( const class ON_OBSOLETE_V2_TextDot& V2_text_dot, const class ON_3dmAnnotationContext* annotation_context, ON_TextDot* destination ) { ON_wString dot_text = V2_text_dot.m_text; dot_text.TrimLeft(); dot_text.TrimRight(); ON_TextDot* text_dot = (nullptr != destination) ? destination : new ON_TextDot(); text_dot->SetPrimaryText(dot_text); text_dot->SetCenterPoint(V2_text_dot.point); return text_dot; } ON_TextDot::ON_TextDot( ON_3dPoint center_point, const wchar_t* primary_text, const wchar_t* secondary_text ) : m_center_point( center_point.IsValid() ? center_point : ON_3dPoint::UnsetPoint ) , m_primary_text(primary_text) , m_secondary_text(secondary_text) { } ON_TextDot::~ON_TextDot() {} void ON_TextDot::EmergencyDestroy() { m_center_point = ON_3dPoint::UnsetPoint; m_primary_text.EmergencyDestroy(); m_secondary_text.EmergencyDestroy(); m_font_face.EmergencyDestroy(); m_height_in_points = ON_TextDot::DefaultHeightInPoints; m_display_bits = 0; } bool ON_TextDot::IsValid( ON_TextLog* text_log ) const { // 5/6/03 LW made dots with no text valid. if ( !m_center_point.IsValid() ) { if ( 0 != text_log ) { text_log->Print("ON_TextDot::CenterPoint() is not valid\n"); } return false; } return true; } void ON_TextDot::Dump( ON_TextLog& log) const { log.Print(L"Center: "); log.Print( m_center_point); log.Print(L"\n"); log.Print(L"Primary text: \"%ls\"\n", static_cast(m_primary_text)); log.Print(L"Secondary text: \"%ls\"\n", static_cast(m_secondary_text)); log.Print(L"Height in points: %d\n", m_height_in_points); log.Print(L"Font face: \"%ls\"\n", static_cast(m_font_face)); } bool ON_TextDot::Write( ON_BinaryArchive& file) const { bool rc = false; for (;;) { const int minor_version = file.Archive3dmVersion() >= 60 ? 1 : 0; if (!file.Write3dmChunkVersion(1, minor_version)) break; if (!file.WritePoint(m_center_point)) break; if (!file.WriteInt(m_height_in_points)) break; if (!file.WriteString(m_primary_text)) break; if (!file.WriteString(m_font_face)) break; // June 21, 2015 // Dale Lear cleaned this up so runtime bits and file format are independent. // DO NOT modify this display_bits code for future bool values. int display_bits = 0; if ( AlwaysOnTop() ) display_bits |= 1; if ( Transparent() ) display_bits |= 2; if ( Bold() ) display_bits |= 4; if (Italic() ) display_bits |= 8; if (!file.WriteInt(display_bits)) break; // DO NOT use display bits for future bool values if (minor_version >= 1) { // version 1.1 fields June 21, 2015 if (!file.WriteString(m_secondary_text)) break; } rc = true; break; } return rc; } bool ON_TextDot::Read( ON_BinaryArchive& file) { bool rc = false; *this = ON_TextDot::Unset; int major_version = 0; int minor_version = 0; while (file.Read3dmChunkVersion(&major_version, &minor_version)) { if (1 != major_version) break; ON_3dPoint center_point; if (!file.ReadPoint(center_point)) break; SetCenterPoint(center_point); int height; if (!file.ReadInt(&height)) break; SetHeightInPoints(height); ON_wString str; if (!file.ReadString( str)) break; SetPrimaryText(str); if (!file.ReadString( str)) break; SetFontFace(str); // June 21, 2015 // Dale Lear cleaned this up so runtime bits and file format are independent. // DO NOT use display bits for future bool values int display_bits = 0; if (!file.ReadInt( &display_bits)) break; SetAlwaysOnTop( 0 != (1 & display_bits) ); SetTransparent( 0 != (2 & display_bits) ); SetBold( 0 != (4 & display_bits) ); SetItalic( 0 != (8 & display_bits) ); // DO NOT use display bits for future bool values if (minor_version >= 1) { // version 1.1 fields June 21, 2015 if (!file.ReadString(str)) break; SetSecondaryText(str); } rc = true; break; } return rc; } ON::object_type ON_TextDot::ObjectType() const { return ON::text_dot; } int ON_TextDot::Dimension() const { return 3; } bool ON_TextDot::GetBBox( double* box_min, double* box_max, bool grow_box /*= false*/) const { return ON_GetPointListBoundingBox( 3, 0, 1, 3, &m_center_point.x, box_min, box_max, grow_box?true:false ); } bool ON_TextDot::Transform( const ON_Xform& xform) { TransformUserData( xform); return ON_TransformPointList( 3, 0, 1, 3, &m_center_point.x, xform); } bool ON_TextDot::IsDeformable() const { return true; } bool ON_TextDot::MakeDeformable() { return true; } ON_3dPoint ON_TextDot::CenterPoint() const { return m_center_point; } void ON_TextDot::SetCenterPoint( ON_3dPoint center_point ) { m_center_point = center_point; } int ON_TextDot::HeightInPoints() const { // in "points" return m_height_in_points; } void ON_TextDot::SetHeightInPoints( int height_in_points ) { if( height_in_points >= ON_TextDot::MinimumHeightInPoints ) m_height_in_points = height_in_points; } const wchar_t* ON_TextDot::PrimaryText() const { return static_cast< const wchar_t* >(m_primary_text); } const wchar_t* ON_TextDot::SecondaryText() const { return static_cast< const wchar_t* >(m_secondary_text); } static void SetDotText( const wchar_t* dot_text, bool bCRtoCRLF, ON_wString& dot_string ) { if (nullptr != dot_text) { // strip leading white space while ( dot_text[0] > 0 && dot_text[0] <= 0x20 ) dot_text++; } size_t len = ON_wString::Length(dot_text); // strip trailing white space while (len > 0 && dot_text[len-1] <= 0x20 && dot_text[len-1] > 0) len--; if( len > 0 ) { wchar_t* buffer = (wchar_t*)onmalloc((2 * len + 1)*sizeof(wchar_t)); size_t j = 0; for (size_t i = 0; i < len; i++) { if (bCRtoCRLF && '\r' == dot_text[i] && '\n' != dot_text[i+1]) { // change \r to \r\n buffer[j++] = '\r'; buffer[j++] = '\n'; } else { buffer[j++] = dot_text[i]; } } buffer[j] = 0; dot_string = buffer; onfree(buffer); } else { dot_string = ON_wString::EmptyString; } } void ON_TextDot::SetPrimaryText(const wchar_t* primary_dot_text) { SetDotText(primary_dot_text,true,m_primary_text); } void ON_TextDot::SetSecondaryText(const wchar_t* secondary_dot_text) { SetDotText(secondary_dot_text,true,m_secondary_text); } const wchar_t* ON_TextDot::FontFace() const { return m_font_face.IsEmpty() ? ON_TextDot::DefaultFontFace : static_cast< const wchar_t* >(m_font_face); } void ON_TextDot::SetFontFace( const wchar_t* font_face ) { SetDotText(font_face, true, m_font_face); } static void SetDisplayBitsFromBool( bool b, unsigned int bit, unsigned int& display_bits ) { if (b) display_bits |= bit; else display_bits &= (~bit); } static bool DisplayBitsToBool( unsigned int display_bits, unsigned int bit ) { return (bit == (display_bits & bit) ? true : false); } void ON_TextDot::SetAlwaysOnTop( bool bAlwaysOnTop ) { SetDisplayBitsFromBool(bAlwaysOnTop,1,m_display_bits); } bool ON_TextDot::AlwaysOnTop() const { return DisplayBitsToBool(m_display_bits,1); } void ON_TextDot::SetTransparent( bool bTransparent ) { SetDisplayBitsFromBool(bTransparent,2,m_display_bits); } bool ON_TextDot::Transparent() const { return DisplayBitsToBool(m_display_bits,2); } void ON_TextDot::SetBold( bool bBold ) { SetDisplayBitsFromBool(bBold,4,m_display_bits); } bool ON_TextDot::Bold() const { return DisplayBitsToBool(m_display_bits,4); } void ON_TextDot::SetItalic(bool bItalic) { SetDisplayBitsFromBool(bItalic,8,m_display_bits); } bool ON_TextDot::Italic() const { return DisplayBitsToBool(m_display_bits,8); } //////// deprecated functions ///////// const ON_3dPoint& ON_TextDot::Point() const { //Perform same functionality as CenterPoint return m_center_point; } void ON_TextDot::SetPoint(const ON_3dPoint& point) { SetCenterPoint(point); } const wchar_t* ON_TextDot::TextString() const { return PrimaryText(); } void ON_TextDot::SetTextString(const wchar_t* string) { SetPrimaryText(string); } //////////////////////////////////////// ON_OBSOLETE_V5_AnnotationText::ON_OBSOLETE_V5_AnnotationText() { memset(&m_rect,0,sizeof(m_rect)); } ON_OBSOLETE_V5_AnnotationText::~ON_OBSOLETE_V5_AnnotationText() { } ON_OBSOLETE_V5_AnnotationText& ON_OBSOLETE_V5_AnnotationText::operator=(const char* s) { SetText(s); return *this; } ON_OBSOLETE_V5_AnnotationText& ON_OBSOLETE_V5_AnnotationText::operator=(const wchar_t* s) { SetText(s); return *this; } void ON_OBSOLETE_V5_AnnotationText::SetText(const char* s) { ON_wString::operator=(s); memset(&m_rect,0,sizeof(m_rect)); } void ON_OBSOLETE_V5_AnnotationText::SetText(const wchar_t* s) { ON_wString::operator=(s); memset(&m_rect,0,sizeof(m_rect)); } bool ON_OBSOLETE_V5_Annotation::GetTextXform( ON_OBSOLETE_V5_RECT gdi_text_rect, const ON_Font& font, const ON_DimStyle* dimstyle, double dimscale, const ON_Viewport* vp, const ON_Xform* model_xform, ON_Xform& xform ) const { int gdi_height_of_I = font.FontMetrics().AscentOfI(); const double textheight = dimstyle ? dimstyle->TextHeight() : m_textheight; double textgap = dimstyle ? dimstyle->TextGap() : 0.0; const ON_INTERNAL_OBSOLETE::V5_TextDisplayMode textalignment = dimstyle ? ON_INTERNAL_OBSOLETE::V5TextDisplayModeFromV6DimStyle(*dimstyle) : ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kNormal; const ON_3dVector cameraX = (vp) ? vp->CameraX() : m_plane.xaxis; const ON_3dVector cameraY = (vp) ? vp->CameraY() : m_plane.yaxis; if(dimstyle) { // - Oct 4, 07 LW Get correct text gap using // multi-line tolerance text since GetTextXform doesn't do that. if( ( ON_DimStyle::tolerance_format::Deviation == dimstyle->ToleranceFormat() || ON_DimStyle::tolerance_format::Limits == dimstyle->ToleranceFormat() ) && ( Type() == ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear || Type() == ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned) ) textgap += textheight * 0.5; } return GetTextXform( gdi_text_rect, gdi_height_of_I, textheight, textgap, textalignment, dimscale, cameraX, cameraY, model_xform, xform ); } static bool GetLeaderEndAndDirection( const ON_OBSOLETE_V5_Annotation* pAnn, ON_2dPoint& E, ON_2dVector& R ) { bool rc = false; ON_INTERNAL_OBSOLETE::V5_eAnnotationType ann_type = pAnn->m_type; const ON_2dPointArray& ann_m_points = pAnn->m_points; R.Set(1.0,0.0); // unit vector points to end E.Set(0.0,0.0); // end point if ( ann_m_points.Count() >= 4 && (ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter == ann_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius == ann_type) ) { E = ann_m_points[2]; // end of radial dimension R = E - ann_m_points[3]; if ( !R.Unitize() ) { R = E - ann_m_points[1]; if ( !R.Unitize() ) { R = E - ann_m_points[0]; if ( !R.Unitize() ) { R.Set(1.0,0.0); } } } rc = true; } else if ( ann_m_points.Count() >= 2 && ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader == ann_type ) { int i; E = *ann_m_points.Last(); for (i = ann_m_points.Count()-2; i >= 0; i-- ) { R = E - ann_m_points[i]; if ( R.Unitize() ) { break; } R.Set(1.0,0.0); } rc = true; } else if ( ann_m_points.Count() >= 2 && ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate == ann_type ) { E = ann_m_points[1]; int direction = (( ON_OBSOLETE_V5_DimOrdinate*)pAnn)->Direction(); if( direction == -1) { if( fabs( ann_m_points[1].x - ann_m_points[0].x) <= fabs( ann_m_points[1].y - ann_m_points[0].y)) direction = 0; else direction = 1; } if( direction == 0) R.Set( 0.0, ann_m_points[1].y - ann_m_points[0].y); else R.Set( ann_m_points[1].x - ann_m_points[0].x, 0.0); if( !R.Unitize()) R.Set(1.0,0.0); rc = true; } return rc; } // Oct 30, 07 - LW // This function should not be used any longer bool ON_OBSOLETE_V5_Annotation::GetTextXform( ON_OBSOLETE_V5_RECT gdi_text_rect, int gdi_height_of_I, double dimstyle_textheight, double dimstyle_textgap, ON_INTERNAL_OBSOLETE::V5_TextDisplayMode dimstyle_textalignment, double dimscale, ON_3dVector cameraX, ON_3dVector cameraY, ON_Xform& xform ) const { ON_ERROR("This function should not be used. Use the version that takes a model transform argument."); return false; } //const ON_OBSOLETE_V5_Annotation* ann = this; //const ON_INTERNAL_OBSOLETE::V5_eAnnotationType ann_type = ann->m_type; //if ( 0 == gdi_height_of_I ) //{ // // Default to height of Ariel 'I' // gdi_height_of_I = (165*ON_Font::Constants::AnnotationFontCellHeight)/256; //} //if ( 0.0 == dimscale ) //{ // dimscale = 1.0; //} //dimstyle_textheight *= dimscale; //dimstyle_textgap *= dimscale; //double textheight = ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock == ann_type ) // ? m_textheight*dimscale // : dimstyle_textheight; //if ( 0.0 == textheight ) // textheight = 1.0; //ON_3dVector cameraZ = ON_CrossProduct( cameraX, cameraY ); //if ( fabs( 1.0 - cameraZ.Length() ) > ON_SQRT_EPSILON ) //{ // cameraZ.Unitize(); //} //// This xform is a scale from Windows gdi coordinates //// to annotation plane coordinates. //const double gdi_to_plane_scale = textheight/gdi_height_of_I; //ON_Xform gdi_to_plane(1.0); //gdi_to_plane.m_xform[0][0] = gdi_to_plane_scale; //gdi_to_plane.m_xform[1][1] = -gdi_to_plane_scale; //// width and height of text line in Rhino units. //const double text_line_width = gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left); ////const double text_line_height = gdi_to_plane_scale*(gdi_text_rect.bottom - gdi_text_rect.top); //if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock == ann_type ) //{ // // The orientation of the text is text blocks // // does not depend on the view or text alignment // // settings. The position and orientation of // // the text in every other annotation depends on // // the view and text alignment settings. // // // // It simplifies the code for the rest of the // // annotation settings to quickly deal with text // // blocks here. // ON_Xform plane_to_world(1.0); // plane_to_world.Rotation(ON_xy_plane,ann->m_plane); // xform = plane_to_world*gdi_to_plane; // return true; //} //// text_position_mode //// 1 = linear, aligned, or anglular dimension //// (dimension definition determines center point of text box) //// 2 = radial, diameter, leader //// (dimension definition determined end point of text box) //int position_style = 0; //switch( ann_type ) //{ //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: // // dimension definition determines center point of text box // position_style = 1; // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate: // // dimension definition determines end of text box // position_style = 2; // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtNothing: // break; //} //// This translation puts the center of the fist line of text at //// (0,0) in the annotation's plane. //if ( ON::dtHorizontal != dimstyle_textalignment || 1 == position_style ) //{ // gdi_to_plane.m_xform[0][3] = -0.5*text_line_width; // gdi_to_plane.m_xform[0][3] = -0.5*text_line_width; //} //gdi_to_plane.m_xform[1][3] = -0.5*textheight; //if ( ON::dtHorizontal != dimstyle_textalignment ) //{ // if ( ((cameraZ*m_plane.zaxis) < -ON_SQRT_EPSILON) ) // { // // Viewing dimension from the backside // ON_Xform flip(1.0); // switch ( position_style ) // { // case 1: // ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular // flip.m_xform[0][0] = -1.0; // flip.m_xform[0][3] = gdi_text_rect.left + gdi_text_rect.right; // break; // case 2: // ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader // flip.m_xform[1][1] = -1.0; // flip.m_xform[1][3] = gdi_text_rect.top + gdi_text_rect.bottom; // break; // } // gdi_to_plane = gdi_to_plane*flip; // } //} //// text_centering_rotation rotates about the "center". Angular, //// radial, and leader dimensions use this rotation. //ON_2dVector text_centering_rotation(1.0,0.0); //// text_centering_translation is a small translation deals with //// text that is above or to the right of the "center" point. //// It is no larger than dimstyle_gap + 1/2 the size of the //// text's bounding box. //ON_2dVector text_centering_translation(0.0,0.0); //double x, y; //if ( ON::dtHorizontal != dimstyle_textalignment ) //{ // if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear == ann_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned == ann_type ) // { // if ( ON::dtAboveLine == dimstyle_textalignment ) // { // text_centering_translation.y = 0.5*textheight+dimstyle_textgap; // } // y = ann->m_plane.yaxis*cameraY; // x = -ann->m_plane.yaxis*cameraX; // if ( fabs(y) <= ON_SQRT_EPSILON && fabs(x) > ON_SQRT_EPSILON ) // { // y = x; // } // if ( y < 0.0 ) // { // text_centering_translation.Reverse(); // text_centering_rotation.Reverse(); // rotate 180 degrees // } // } // else if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular == ann_type ) // { // // This transform rotates the text in the annotation plane. // const ON_OBSOLETE_V5_DimAngular* angular_dim = ON_OBSOLETE_V5_DimAngular::Cast(ann); // if ( 0 != angular_dim ) // { // double a = 0.5*angular_dim->m_angle; // ON_2dVector R(cos(a),sin(a)); // a -= 0.5*ON_PI; // text_centering_rotation.x = cos(a); // text_centering_rotation.y = sin(a); // ON_3dVector V = R.x*m_plane.xaxis + R.y*m_plane.yaxis; // x = V*cameraX; // y = V*cameraY; // if ( fabs(y) <= ON_SQRT_EPSILON && fabs(x) > ON_SQRT_EPSILON ) // { // y = -x; // } // if ( y < 0.0 ) // { // text_centering_rotation.Reverse(); // add another 180 degrees of rotation // } // if ( ON::dtAboveLine == dimstyle_textalignment ) // { // y = 0.5*textheight + dimstyle_textgap; // text_centering_translation.x = -y*text_centering_rotation.y; // text_centering_translation.y = y*text_centering_rotation.x; // } // } // } // else if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter == ann_type // || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius == ann_type // || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader == ann_type // || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate == ann_type) // { // ON_2dPoint E(0.0,0.0); // end point // ON_2dVector R(1.0,0.0); // unit vector from penultimate point to end point // GetLeaderEndAndDirection( this, E, R ); // text_centering_rotation = R; // text_centering_translation = (dimstyle_textgap + 0.5*text_line_width)*text_centering_rotation; // ON_3dVector V = text_centering_rotation.x*m_plane.xaxis + text_centering_rotation.y*m_plane.yaxis; // x = V*cameraX; // y = V*cameraY; // if ( fabs(x) <= ON_SQRT_EPSILON && fabs(y) > ON_SQRT_EPSILON ) // { // x = y; // } // if ( x < 0.0 ) // { // text_centering_rotation.Reverse(); // rotate 180 degrees // } // } //} //ON_Xform text_centering_xform(1.0); //text_centering_xform.m_xform[0][0] = text_centering_rotation.x; //text_centering_xform.m_xform[0][1] = -text_centering_rotation.y; //text_centering_xform.m_xform[1][0] = text_centering_rotation.y; //text_centering_xform.m_xform[1][1] = text_centering_rotation.x; //// Since the translation happens after the rotation about (0,0), //// we can just tack it on here. //text_centering_xform.m_xform[0][3] = text_centering_translation.x; //text_centering_xform.m_xform[1][3] = text_centering_translation.y; //// This transform translates the text in the annotation plane //// It can be a large translation //ON_2dVector text_offset_translation(0.0,0.0); // CRhinoText::Offset() = text->Offset() //switch( ann_type ) //{ //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: // if ( m_points.Count() >= ON_OBSOLETE_V5_DimLinear::dim_pt_count ) // { // const ON_OBSOLETE_V5_DimLinear* linear_dim = ON_OBSOLETE_V5_DimLinear::Cast(ann); // if ( linear_dim ) // { // text_offset_translation = linear_dim->Dim2dPoint(ON_OBSOLETE_V5_DimLinear::text_pivot_pt); // } // } // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: // if ( m_points.Count() >= ON_OBSOLETE_V5_DimAngular::dim_pt_count ) // { // const ON_OBSOLETE_V5_DimAngular* angular_dim = ON_OBSOLETE_V5_DimAngular::Cast(ann); // if ( angular_dim ) // { // text_offset_translation = angular_dim->Dim2dPoint(ON_OBSOLETE_V5_DimAngular::text_pivot_pt); // } // } // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: // if ( m_points.Count() >= ON_OBSOLETE_V5_DimRadial::dim_pt_count ) // { // // No user positioned text on radial dimensions. // text_offset_translation = m_points[ON_OBSOLETE_V5_DimRadial::tail_pt_index]; // } // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader: // if ( m_points.Count() > 0 ) // { // // No user positioned text on leaders. // text_offset_translation = *m_points.Last(); // } // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate: // if ( m_points.Count() == 2 ) // { // // No user positioned text on leaders. // text_offset_translation = m_points[1]; // } // break; //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock: //case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtNothing: // break; //} //ON_Xform plane_translation(1.0); //plane_translation.m_xform[0][3] = text_offset_translation.x; //plane_translation.m_xform[1][3] = text_offset_translation.y; //// this transform maps a point in the annotation plane to world coordinates //ON_Xform plane_to_world(1.0); //plane_to_world.Rotation(ON_xy_plane,ann->m_plane); //ON_Xform horizonal_xform(1.0); //if ( ON::dtHorizontal == dimstyle_textalignment ) //{ // ON_3dPoint fixed_point = ann->m_plane.PointAt(text_offset_translation.x,text_offset_translation.y); // horizonal_xform.Rotation( // fixed_point, // ann->m_plane.xaxis, // ann->m_plane.yaxis, // ann->m_plane.zaxis, // fixed_point, // cameraX, // cameraY, // cameraZ // ); // if ( 2 == position_style ) // { // // leaders, radial, and diameter // ON_2dPoint E(0.0,0.0); // end point // ON_2dVector R(1.0,0.0); // unit vector from penultimate point to end point // GetLeaderEndAndDirection( this, E, R ); // ON_3dVector V = R.x*m_plane.xaxis + R.y*m_plane.yaxis; // x = V*cameraX; // y = ( x > -ON_SQRT_EPSILON ) // ? dimstyle_textgap // : -(dimstyle_textgap + text_line_width); // V = y*cameraX; // horizonal_xform.m_xform[0][3] += V.x; // horizonal_xform.m_xform[1][3] += V.y; // horizonal_xform.m_xform[2][3] += V.z; // } //} //ON_Xform gdi_to_world; //gdi_to_world = horizonal_xform // * plane_to_world // * plane_translation // * text_centering_xform // * gdi_to_plane; //xform = gdi_to_world; //return true; //} //static bool do_plane_translation = true; //static bool do_text_centering_xform = true; //static bool do_text_centering_rotation = true; //static bool do_text_centering_translation = true; //static bool do_mirror_flip = true; //static bool do_flip_x = true; //static bool do_flip_y = true; // New function added Oct 30, 07 - LW // To use model xform to draw annotation in blocks correctly bool ON_OBSOLETE_V5_Annotation::GetTextXform( ON_OBSOLETE_V5_RECT gdi_text_rect, int gdi_height_of_I, double dimstyle_textheight, double dimstyle_textgap, ON_INTERNAL_OBSOLETE::V5_TextDisplayMode dimstyle_textalignment, double dimscale, ON_3dVector cameraX, ON_3dVector cameraY, const ON_Xform* model_xform, ON_Xform& xform ) const { ON_Xform mxi; if( model_xform) { mxi = model_xform->Inverse(); cameraX.Transform( mxi); cameraY.Transform( mxi); } const ON_OBSOLETE_V5_Annotation* ann = this; const ON_INTERNAL_OBSOLETE::V5_eAnnotationType ann_type = ann->m_type; if ( 0 == gdi_height_of_I ) { // Default to height of Ariel 'I' gdi_height_of_I = (165*ON_Font::Constants::AnnotationFontCellHeight)/256; } if ( 0.0 == dimscale ) { dimscale = 1.0; } dimstyle_textheight *= dimscale; dimstyle_textgap *= dimscale; double textheight = ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock == ann_type ) ? m_textheight*dimscale : dimstyle_textheight; if ( 0.0 == textheight ) textheight = 1.0; ON_3dVector cameraZ = ON_CrossProduct( cameraX, cameraY ); if ( fabs( 1.0 - cameraZ.Length() ) > ON_SQRT_EPSILON ) { cameraZ.Unitize(); } // This xform is a scale from Windows gdi coordinates // to annotation plane coordinates. const double gdi_to_plane_scale = textheight/gdi_height_of_I; ON_Xform gdi_to_plane(ON_Xform::IdentityTransformation); gdi_to_plane.m_xform[0][0] = gdi_to_plane_scale; gdi_to_plane.m_xform[1][1] = -gdi_to_plane_scale; // width and height of text line in Rhino units. const double text_line_width = gdi_to_plane_scale*(gdi_text_rect.right - gdi_text_rect.left); //const double text_line_height = gdi_to_plane_scale*(gdi_text_rect.bottom - gdi_text_rect.top); if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock == ann_type ) { // The orientation of the text is text blocks // does not depend on the view or text alignment // settings. The position and orientation of // the text in every other annotation depends on // the view and text alignment settings. // // It simplifies the code for the rest of the // annotation settings to quickly deal with text // blocks here. ON_Xform plane_to_world(ON_Xform::IdentityTransformation); plane_to_world.Rotation(ON_xy_plane,ann->m_plane); xform = plane_to_world*gdi_to_plane; return true; } // text_position_mode // 1 = linear, aligned, or anglular dimension // (dimension definition determines center point of text box) // 2 = radial, diameter, leader // (dimension definition determined end point of text box) int position_style = 0; switch( ann_type ) { case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: // dimension definition determines center point of text box position_style = 1; break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader: if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen == dimstyle_textalignment) position_style = 1; else position_style = 2; break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate: // dimension definition determines end of text box position_style = 2; break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtNothing: break; } // This translation puts the center of the fist line of text at // (0,0) in the annotation's plane. if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen != dimstyle_textalignment || 1 == position_style) { if((m_justification & tjRight) == tjRight) gdi_to_plane.m_xform[0][3] = 0.5*text_line_width; else gdi_to_plane.m_xform[0][3] = -0.5*text_line_width; } gdi_to_plane.m_xform[1][3] = -0.5*textheight; if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen != dimstyle_textalignment) { if ( ((cameraZ*m_plane.zaxis) < -ON_SQRT_EPSILON) ) { // Viewing dimension from the backside ON_Xform flip(ON_Xform::IdentityTransformation); switch ( position_style ) { case 1: // ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular flip.m_xform[0][0] = -1.0; flip.m_xform[0][3] = gdi_text_rect.left + gdi_text_rect.right; break; case 2: // ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius, ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader //flip.m_xform[1][1] = -1.0; //flip.m_xform[1][3] = -(gdi_text_rect.top + gdi_text_rect.bottom); break; } gdi_to_plane = gdi_to_plane*flip; } } // text_centering_rotation rotates about the "center". Angular, // radial, and leader dimensions use this rotation. ON_2dVector text_centering_rotation(1.0,0.0); // text_centering_translation is a small translation deals with // text that is above or to the right of the "center" point. // It is no larger than dimstyle_gap + 1/2 the size of the // text's bounding box. ON_2dVector text_centering_translation(0.0,0.0); double x = 1.0, y = 1.0; ON_Xform xfs(ON_Xform::IdentityTransformation); if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen != dimstyle_textalignment) { if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear == ann_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned == ann_type ) { if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine == dimstyle_textalignment) { text_centering_translation.y = 0.5*textheight+dimstyle_textgap; } y = ann->m_plane.yaxis*cameraY; x = -ann->m_plane.yaxis*cameraX; if ( fabs(y) <= ON_SQRT_EPSILON && fabs(x) > ON_SQRT_EPSILON ) { y = x; } if ( y < 0.0 ) { text_centering_translation = -text_centering_translation; text_centering_rotation = -text_centering_rotation; // rotate 180 degrees } } else if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular == ann_type ) { // This transform rotates the text in the annotation plane. const ON_OBSOLETE_V5_DimAngular* angular_dim = ON_OBSOLETE_V5_DimAngular::Cast(ann); if ( 0 != angular_dim ) { double a = 0.5*angular_dim->m_angle; ON_2dVector R(cos(a),sin(a)); a -= 0.5*ON_PI; text_centering_rotation.x = cos(a); text_centering_rotation.y = sin(a); ON_3dVector V = R.x*m_plane.xaxis + R.y*m_plane.yaxis; x = V*cameraX; y = V*cameraY; if ( fabs(y) <= ON_SQRT_EPSILON && fabs(x) > ON_SQRT_EPSILON ) { y = -x; } if ( y < 0.0 ) { text_centering_rotation = -text_centering_rotation; // add another 180 degrees of rotation } if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kAboveLine == dimstyle_textalignment) { y = 0.5*textheight + dimstyle_textgap; text_centering_translation.x = -y*text_centering_rotation.y; text_centering_translation.y = y*text_centering_rotation.x; } } } else if ( ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter == ann_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius == ann_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader == ann_type || ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate == ann_type) { // 30 Jan, 2015 - redid this again rh-29493, rh-29540 ON_2dPoint E(0.0,0.0); // end point ON_2dVector R(1.0,0.0); // unit vector from penultimate point to end point GetLeaderEndAndDirection( this, E, R ); text_centering_rotation = R; text_centering_translation = (dimstyle_textgap + 0.5*text_line_width)*text_centering_rotation; ON_3dPoint p0 = m_plane.origin; ON_3dPoint prx = m_plane.PointAt(R.x, R.y); ON_3dPoint pry = m_plane.PointAt(-R.y, R.x); ON_3dVector xr = prx - p0; // 3d direction of text x ON_3dVector yr = pry - p0; // 3d direction of text y if (xr * cameraX <= ON_ZERO_TOLERANCE) // 22 April 2015 - Lowell - Fixed rh-30239 xfs.m_xform[0][0] = -1.0; if (yr * cameraY <= ON_ZERO_TOLERANCE) xfs.m_xform[1][1] = -1.0; } } else if(ann_type == ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader) { if((m_justification & tjRight) == tjRight) text_centering_translation.Set(-(dimstyle_textgap + 0.5*text_line_width), 0.0); else if((m_justification & tjLeft) == tjLeft) text_centering_translation.Set(dimstyle_textgap + 0.5*text_line_width, 0.0); } ON_Xform text_centering_xform(ON_Xform::IdentityTransformation); text_centering_xform.m_xform[0][0] = text_centering_rotation.x; text_centering_xform.m_xform[0][1] = -text_centering_rotation.y; text_centering_xform.m_xform[1][0] = text_centering_rotation.y; text_centering_xform.m_xform[1][1] = text_centering_rotation.x; text_centering_xform = text_centering_xform * xfs; // Since the translation happens after the rotation about (0,0), // we can just tack it on here. text_centering_xform.m_xform[0][3] = text_centering_translation.x; text_centering_xform.m_xform[1][3] = text_centering_translation.y; // This transform translates the text in the annotation plane // from the plane origin to the final location of the annotation text // It can be a large translation ON_2dVector text_offset_translation(0.0,0.0); // CRhinoText::Offset() = text->Offset() switch( ann_type ) { case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: if ( m_points.Count() >= ON_OBSOLETE_V5_DimLinear::dim_pt_count ) { const ON_OBSOLETE_V5_DimLinear* linear_dim = ON_OBSOLETE_V5_DimLinear::Cast(ann); if ( linear_dim ) { text_offset_translation = linear_dim->Dim2dPoint(ON_OBSOLETE_V5_DimLinear::text_pivot_pt); } } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: if ( m_points.Count() >= ON_OBSOLETE_V5_DimAngular::dim_pt_count ) { const ON_OBSOLETE_V5_DimAngular* angular_dim = ON_OBSOLETE_V5_DimAngular::Cast(ann); if ( angular_dim ) { text_offset_translation = angular_dim->Dim2dPoint(ON_OBSOLETE_V5_DimAngular::text_pivot_pt); } } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: if ( m_points.Count() >= ON_OBSOLETE_V5_DimRadial::dim_pt_count ) { // No user positioned text on radial dimensions. text_offset_translation = m_points[ON_OBSOLETE_V5_DimRadial::tail_pt_index]; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader: if ( m_points.Count() > 0 ) { // No user positioned text on leaders. text_offset_translation = *m_points.Last(); } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate: if ( m_points.Count() == 2 ) { // No user positioned text on leaders. text_offset_translation = m_points[1]; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtNothing: break; } ON_Xform plane_translation(ON_Xform::IdentityTransformation); plane_translation.m_xform[0][3] = text_offset_translation.x; plane_translation.m_xform[1][3] = text_offset_translation.y; // this transform maps a point in the annotation plane to world coordinates ON_Xform plane_to_world(ON_Xform::IdentityTransformation); plane_to_world.Rotation(ON_xy_plane,ann->m_plane); ON_Xform horizonal_xform(ON_Xform::IdentityTransformation); if (ON_INTERNAL_OBSOLETE::V5_TextDisplayMode::kHorizontalToScreen == dimstyle_textalignment) { ON_3dPoint fixed_point = ann->m_plane.PointAt(text_offset_translation.x,text_offset_translation.y); horizonal_xform.Rotation( fixed_point, ann->m_plane.xaxis, ann->m_plane.yaxis, ann->m_plane.zaxis, fixed_point, cameraX, cameraY, cameraZ ); if ( 2 == position_style ) { // leaders, radial, and diameter ON_2dPoint E(0.0,0.0); // end point ON_2dVector R(1.0,0.0); // unit vector from penultimate point to end point GetLeaderEndAndDirection( this, E, R ); ON_3dVector V = R.x*m_plane.xaxis + R.y*m_plane.yaxis; x = V*cameraX; y = ( x > -ON_SQRT_EPSILON ) ? dimstyle_textgap : -(dimstyle_textgap + text_line_width); V = y*cameraX; horizonal_xform.m_xform[0][3] += V.x; horizonal_xform.m_xform[1][3] += V.y; horizonal_xform.m_xform[2][3] += V.z; } } ON_Xform gdi_to_world; gdi_to_world = horizonal_xform * plane_to_world * plane_translation * text_centering_xform * gdi_to_plane; xform = gdi_to_world; return true; } bool ON_OBSOLETE_V5_Annotation::GetTextPoint( ON_2dPoint& text_2d_point ) const { bool rc = false; switch ( m_type ) { case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtTextBlock: text_2d_point.Set(0.0,0.0); rc = true; break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimLinear: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAligned: if ( m_userpositionedtext ) { if ( m_points.Count() >= 5 ) { text_2d_point = m_points[4]; rc = true; } } else if ( m_points.Count() >= 3 ) { text_2d_point.x = 0.5*(m_points[0].x + m_points[2].x); text_2d_point.y = m_points[2].y; rc = true; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtLeader: if ( m_points.Count() > 0 ) { text_2d_point = *m_points.Last(); rc = true; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimAngular: { const ON_OBSOLETE_V5_DimAngular* angular_dim = ON_OBSOLETE_V5_DimAngular::Cast(this); if ( angular_dim ) { if ( m_userpositionedtext ) { if ( m_points.Count() >= 0 ) { text_2d_point = m_points[0]; } } else { text_2d_point.x = angular_dim->m_radius*cos(angular_dim->m_angle); text_2d_point.y = angular_dim->m_radius*sin(angular_dim->m_angle); rc = true; } } } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimRadius: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimDiameter: // no user positioned text if ( m_points.Count() >= 3 ) { text_2d_point = m_points[2]; rc = true; } break; case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtDimOrdinate: case ON_INTERNAL_OBSOLETE::V5_eAnnotationType::dtNothing: break; } return rc; } //////////////////////////////////////////////////////////// // // do not copy or export this class definition. // class /*NEVER PUT THIS CLASS IN THE SDK*/ ON_AnnotationTextFormula : public ON_UserData { #if !defined(BOZO_VACCINE_699FCC4262D4488c9109F1B7A37CE926) #error Never copy this class definition or put this definition in a header file! #endif ON_OBJECT_DECLARE(ON_AnnotationTextFormula); public: ON_AnnotationTextFormula(); ~ON_AnnotationTextFormula(); // NO! - do not add IO support to this userdata! // bool Write(ON_BinaryArchive&) const; // NO! - do not add IO support to this userdata! // bool Read(ON_BinaryArchive&); bool GetDescription(ON_wString&) override; // NO! - do not add IO support to this userdata! // bool Archive() const; static ON_AnnotationTextFormula* Get(const ON_OBSOLETE_V5_Annotation*); static void Set(ON_OBSOLETE_V5_Annotation*,const wchar_t* text_formula); ON_wString m_text_formula; }; #undef BOZO_VACCINE_699FCC4262D4488c9109F1B7A37CE926 ON_OBJECT_IMPLEMENT(ON_AnnotationTextFormula,ON_UserData,"699FCC42-62D4-488c-9109-F1B7A37CE926"); ON_AnnotationTextFormula::~ON_AnnotationTextFormula() {} ON_AnnotationTextFormula::ON_AnnotationTextFormula() { m_userdata_uuid = ON_CLASS_ID(ON_AnnotationTextFormula); m_application_uuid = ON_opennurbs5_id; m_userdata_copycount = 1; } bool ON_AnnotationTextFormula::GetDescription( ON_wString& description ) { description = "Annotation Text Formula"; return true; } ON_AnnotationTextFormula* ON_AnnotationTextFormula::Get(const ON_OBSOLETE_V5_Annotation* p) { return (0 != p) ? ON_AnnotationTextFormula::Cast(p->GetUserData(ON_CLASS_ID(ON_AnnotationTextFormula))) : 0; } void ON_AnnotationTextFormula::Set(ON_OBSOLETE_V5_Annotation* p,const wchar_t* text_formula) { if ( 0 != p ) { ON_AnnotationTextFormula* tf = Get(p); if ( 0 == text_formula || 0 == text_formula[0] ) { if (0 != tf ) delete tf; } else { if ( 0 == tf ) { tf = new ON_AnnotationTextFormula(); p->AttachUserData(tf); } tf->m_text_formula = text_formula; } } } // // do not copy or export this class definition. // //////////////////////////////////////////////////////////// void ON_OBSOLETE_V5_Annotation::SetTextValue( const wchar_t* text_value ) { m_usertext = text_value; } const wchar_t* ON_OBSOLETE_V5_Annotation::TextValue() const { return ((const wchar_t*)m_usertext); } void ON_OBSOLETE_V5_Annotation::SetTextFormula( const wchar_t* text_formula ) { ON_AnnotationTextFormula::Set(this,text_formula); } const wchar_t* ON_OBSOLETE_V5_Annotation::TextFormula() const { const ON_AnnotationTextFormula* tf = ON_AnnotationTextFormula::Get(this); return (0 != tf) ? ((const wchar_t*)tf->m_text_formula) : TextValue(); } bool ON_BinaryArchive::Internal_WriteV2AnnotationObject( const ON_OBSOLETE_V5_Annotation& V5_annotation, const ON_3dmAnnotationContext* annotation_context ) { if (m_3dm_version != 1 && m_3dm_version != 2) { ON_ERROR("m_3dm_version must be 1 or 2"); return false; } const ON_DimStyle* dim_style = nullptr; int archive_dim_style_index = V5_annotation.V5_3dmArchiveDimStyleIndex(); if ( archive_dim_style_index >= 0 && archive_dim_style_index < m_archive_dim_style_table.Count()) dim_style = m_archive_dim_style_table[archive_dim_style_index]; if (nullptr == dim_style) { dim_style = &ArchiveCurrentDimStyle(); archive_dim_style_index = ArchiveCurrentDimStyleIndex(); } //const int V5_3dm_archive_dim_style_index = m_manifest.ItemFromId(ON_ModelComponent::Type::DimStyle, dim_style->Id()).Index(); m_annotation_context.SetReferencedDimStyle(dim_style,nullptr,archive_dim_style_index); if (nullptr == annotation_context) annotation_context = &m_annotation_context; ON_OBSOLETE_V2_Annotation* V2_annotation = ON_OBSOLETE_V2_Annotation::CreateFromV5Annotation( V5_annotation, annotation_context ); bool rc = (nullptr != V2_annotation) ? Internal_WriteObject(*V2_annotation) : Internal_WriteObject(V5_annotation); if (nullptr != V2_annotation) delete V2_annotation; return rc; } ON_INTERNAL_OBSOLETE::V5_vertical_alignment ON_INTERNAL_OBSOLETE::V5VerticalAlignmentFromV5Justification( unsigned int v5_justification_bits ) { ON_INTERNAL_OBSOLETE::V5_vertical_alignment valign = ON_INTERNAL_OBSOLETE::V5_vertical_alignment::Bottom; const unsigned int v5_valign_mask = ON_OBSOLETE_V5_TextObject::eTextJustification::tjBottom | ON_OBSOLETE_V5_TextObject::eTextJustification::tjMiddle | ON_OBSOLETE_V5_TextObject::eTextJustification::tjTop; if (ON_OBSOLETE_V5_TextObject::eTextJustification::tjTop == (v5_justification_bits & v5_valign_mask)) valign = ON_INTERNAL_OBSOLETE::V5_vertical_alignment::Top; else if (ON_OBSOLETE_V5_TextObject::eTextJustification::tjMiddle == (v5_justification_bits & v5_valign_mask)) valign = ON_INTERNAL_OBSOLETE::V5_vertical_alignment::Middle; return valign; } ON_INTERNAL_OBSOLETE::V5_horizontal_alignment ON_INTERNAL_OBSOLETE::V5HorizontalAlignmentFromV5Justification( unsigned int v5_justification_bits ) { ON_INTERNAL_OBSOLETE::V5_horizontal_alignment halign = ON_INTERNAL_OBSOLETE::V5_horizontal_alignment::Left; const unsigned int v5_halign_mask = ON_OBSOLETE_V5_TextObject::eTextJustification::tjLeft | ON_OBSOLETE_V5_TextObject::eTextJustification::tjCenter | ON_OBSOLETE_V5_TextObject::eTextJustification::tjRight; if (ON_OBSOLETE_V5_TextObject::eTextJustification::tjCenter == (v5_justification_bits & v5_halign_mask)) halign = ON_INTERNAL_OBSOLETE::V5_horizontal_alignment::Center; else if (ON_OBSOLETE_V5_TextObject::eTextJustification::tjRight == (v5_justification_bits & v5_halign_mask)) halign = ON_INTERNAL_OBSOLETE::V5_horizontal_alignment::Right; return halign; }