mirror of
https://github.com/mcneel/opennurbs.git
synced 2026-09-04 00:50:16 +08:00
Sync changes from upstream repository
This commit is contained in:
@@ -960,6 +960,12 @@ public:
|
||||
//---------------------------
|
||||
// ON_Object overrides
|
||||
|
||||
// virtual ON_Object::SizeOf override
|
||||
unsigned int SizeOf() const override;
|
||||
|
||||
// virtual ON_Object::DataCRC override
|
||||
ON__UINT32 DataCRC(ON__UINT32 current_remainder) const override;
|
||||
|
||||
bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
|
||||
|
||||
/*
|
||||
|
||||
@@ -196,7 +196,13 @@ ON_TextContent* ON_Dimension::RebuildDimensionText(
|
||||
}
|
||||
else
|
||||
{
|
||||
displaytext = displaytext + UserText();
|
||||
// October 2, 2025 - Tim
|
||||
// As far as I can tell RebuildDimensionText only gets called with
|
||||
// expandanglebrackets set to false from the acad export plugin otherwise
|
||||
// I would be jumpy about making these changes.
|
||||
// These changes fix https://mcneel.myjetbrains.com/youtrack/issue/RH-89323
|
||||
|
||||
displaytext = PlainText();
|
||||
if (dimstyle->Prefix().IsNotEmpty() || dimstyle->Suffix().IsNotEmpty())
|
||||
{
|
||||
int ci = displaytext.Find(L"<>");
|
||||
@@ -206,7 +212,7 @@ ON_TextContent* ON_Dimension::RebuildDimensionText(
|
||||
if (displaytext.Length() > ci + 2)
|
||||
right = displaytext.Right(displaytext.Length() - ci - 2);
|
||||
displaytext = displaytext.Left(ci);
|
||||
displaytext = displaytext + dimstyle->Prefix();
|
||||
displaytext = dimstyle->Prefix() + displaytext;
|
||||
displaytext = displaytext + L"<>";
|
||||
displaytext = displaytext + dimstyle->Suffix();
|
||||
displaytext = displaytext + right;
|
||||
|
||||
+2
-2
@@ -5554,7 +5554,7 @@ const ON_ClassArray< ON_FontFaceQuartet >& ON_FontList::QuartetList() const
|
||||
&& ssw_dex.j >= 0 && ssw_dex.j < 2
|
||||
&& ssw_dex.k >= 1 && ssw_dex.k < max_weight_dex
|
||||
)
|
||||
? fonts_by_ssw[ssw_dex.i][ssw_dex.k][ssw_dex.k]
|
||||
? fonts_by_ssw[ssw_dex.i][ssw_dex.j][ssw_dex.k]
|
||||
: nullptr;
|
||||
if (nullptr != cleanf)
|
||||
{
|
||||
@@ -7638,7 +7638,7 @@ const ON_wString ON_Font::FakeWindowsLogfontNameFromFamilyAndPostScriptNames(
|
||||
Internal_FakeWindowsLogfontName(L"Avenir", L"Avenir-Heavy", L"Avenir Heavy", ON_FontFaceQuartet::Member::Regular),
|
||||
Internal_FakeWindowsLogfontName(L"Avenir", L"Avenir-HeavyOblique", L"Avenir Heavy", ON_FontFaceQuartet::Member::Italic),
|
||||
Internal_FakeWindowsLogfontName(L"Avenir", L"Avenir-Black", L"Avenir Black", ON_FontFaceQuartet::Member::Regular),
|
||||
Internal_FakeWindowsLogfontName(L"Avenir", L"Avenir-BlackOblique", L"Avenir-Black", ON_FontFaceQuartet::Member::Italic),
|
||||
Internal_FakeWindowsLogfontName(L"Avenir", L"Avenir-BlackOblique", L"Avenir Black", ON_FontFaceQuartet::Member::Italic),
|
||||
|
||||
Internal_FakeWindowsLogfontName(L"Avenir Next", L"AvenirNext-UltraLight", L"Avenir Next Ultralight", ON_FontFaceQuartet::Member::Regular),
|
||||
Internal_FakeWindowsLogfontName(L"Avenir Next", L"AvenirNext-UltraLightItalic", L"Avenir Next Ultralight", ON_FontFaceQuartet::Member::Italic),
|
||||
|
||||
@@ -1761,6 +1761,21 @@ bool ON_InstanceRef::IsValid( ON_TextLog* text_log ) const
|
||||
return true;
|
||||
}
|
||||
|
||||
unsigned int ON_InstanceRef::SizeOf() const
|
||||
{
|
||||
unsigned int sz = ON_Geometry::SizeOf();
|
||||
sz += (sizeof(*this) - sizeof(ON_Geometry));
|
||||
return sz;
|
||||
}
|
||||
|
||||
ON__UINT32 ON_InstanceRef::DataCRC(ON__UINT32 current_remainder) const
|
||||
{
|
||||
current_remainder = ON_CRC32(current_remainder, sizeof(m_instance_definition_uuid), &m_instance_definition_uuid);
|
||||
current_remainder = ON_CRC32(current_remainder, sizeof(m_xform), &m_xform);
|
||||
current_remainder = ON_CRC32(current_remainder, sizeof(m_bbox), &m_bbox);
|
||||
return current_remainder;
|
||||
}
|
||||
|
||||
bool ON_InstanceRef::Write(
|
||||
ON_BinaryArchive& binary_archive
|
||||
) const
|
||||
|
||||
@@ -657,14 +657,22 @@ public:
|
||||
// virtual ON_Object overrides
|
||||
//
|
||||
bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
|
||||
|
||||
bool Write(
|
||||
ON_BinaryArchive& binary_archive
|
||||
) const override;
|
||||
|
||||
bool Read(
|
||||
ON_BinaryArchive& binary_archive
|
||||
) override;
|
||||
ON::object_type ObjectType() const override;
|
||||
|
||||
// virtual ON_Object::SizeOf override
|
||||
unsigned int SizeOf() const override;
|
||||
|
||||
// virtual ON_Object::DataCRC override
|
||||
ON__UINT32 DataCRC(ON__UINT32 current_remainder) const override;
|
||||
|
||||
/////////////////////////////////////////////////////////////
|
||||
//
|
||||
// virtual ON_Geometry overrides
|
||||
|
||||
@@ -5645,6 +5645,27 @@ void ON_TextDot::EmergencyDestroy()
|
||||
m_display_bits = 0;
|
||||
}
|
||||
|
||||
unsigned int ON_TextDot::SizeOf() const
|
||||
{
|
||||
unsigned int sz = ON_Geometry::SizeOf();
|
||||
sz += (sizeof(*this) - sizeof(ON_Geometry));
|
||||
sz += m_primary_text.SizeOf();
|
||||
sz += m_secondary_text.SizeOf();
|
||||
sz += m_font_face.SizeOf();
|
||||
return sz;
|
||||
}
|
||||
|
||||
ON__UINT32 ON_TextDot::DataCRC(ON__UINT32 current_remainder) const
|
||||
{
|
||||
current_remainder = m_center_point.DataCRC(current_remainder);
|
||||
current_remainder = m_primary_text.DataCRC(current_remainder);
|
||||
current_remainder = m_secondary_text.DataCRC(current_remainder);
|
||||
current_remainder = m_font_face.DataCRC(current_remainder);
|
||||
current_remainder = ON_CRC32(current_remainder, sizeof(m_display_bits), &m_display_bits);
|
||||
current_remainder = ON_CRC32(current_remainder, sizeof(m_height_in_points), &m_height_in_points);
|
||||
return current_remainder;
|
||||
}
|
||||
|
||||
bool ON_TextDot::IsValid(
|
||||
ON_TextLog* text_log
|
||||
) const
|
||||
|
||||
@@ -470,6 +470,7 @@ unsigned int ON_Mesh::SizeOf() const
|
||||
{
|
||||
unsigned int sz = ON_Geometry::SizeOf();
|
||||
sz += m_V.SizeOfArray();
|
||||
sz += m_dV.SizeOfArray();
|
||||
sz += m_F.SizeOfArray();
|
||||
sz += m_N.SizeOfArray();
|
||||
sz += m_FN.SizeOfArray();
|
||||
|
||||
@@ -5241,10 +5241,10 @@ ON_Plane ON_Plane::FromPointList(
|
||||
//
|
||||
ON_3dVector N(ON_3dVector::ZeroVector);
|
||||
ON_3dVector X(ON_3dVector::UnsetVector);
|
||||
const unsigned int index_0123[4] = { 0,1,2,3 };
|
||||
if ( point_index_count <= 4 )
|
||||
{
|
||||
// use "standard" face normal for quads and triangles.
|
||||
const unsigned int index_0123[4] = {0,1,2,3};
|
||||
if ( 0 == point_index_list )
|
||||
point_index_list = index_0123;
|
||||
Pi0 = point_list[point_index_list[point_stride*(point_count-1)]];
|
||||
|
||||
@@ -132,6 +132,7 @@ void ON_PointCloud::Dump( ON_TextLog& dump ) const
|
||||
const bool bHasNormals = HasPointNormals();
|
||||
const bool bHasColors = HasPointColors();
|
||||
const bool bHasHiddenPoints = (HiddenPointCount() > 0);
|
||||
const bool bHasPointValues = HasPointValues();
|
||||
const int point_count = m_P.Count();
|
||||
dump.Print("ON_PointCloud: %d points\n",point_count);
|
||||
dump.PushIndent();
|
||||
@@ -156,6 +157,11 @@ void ON_PointCloud::Dump( ON_TextLog& dump ) const
|
||||
dump.Print(", color = ");
|
||||
dump.PrintRGB(m_C[i]);
|
||||
}
|
||||
if (bHasPointValues) // 20-Jan-2026 show point value
|
||||
{
|
||||
dump.Print(", value = ");
|
||||
dump.Print(m_V[i]);
|
||||
}
|
||||
if (bHasHiddenPoints && m_H[i])
|
||||
{
|
||||
dump.Print(" (hidden)");
|
||||
|
||||
+12
-12
@@ -6,17 +6,17 @@
|
||||
|
||||
// To update version numbers, edit ..\build\build_dates.msbuild
|
||||
#define RMA_VERSION_MAJOR 8
|
||||
#define RMA_VERSION_MINOR 26
|
||||
#define RMA_VERSION_MINOR 29
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
//
|
||||
// These are set automatically by the build system as the
|
||||
// first step in each build.
|
||||
//
|
||||
#define RMA_VERSION_YEAR 2025
|
||||
#define RMA_VERSION_MONTH 12
|
||||
#define RMA_VERSION_DATE 15
|
||||
#define RMA_VERSION_HOUR 19
|
||||
#define RMA_VERSION_YEAR 2026
|
||||
#define RMA_VERSION_MONTH 3
|
||||
#define RMA_VERSION_DATE 4
|
||||
#define RMA_VERSION_HOUR 11
|
||||
#define RMA_VERSION_MINUTE 0
|
||||
|
||||
////////////////////////////////////////////////////////////////
|
||||
@@ -35,20 +35,20 @@
|
||||
// 3 = build system release build
|
||||
#define RMA_VERSION_BRANCH 0
|
||||
|
||||
#define VERSION_WITH_COMMAS 8,26,25349,19000
|
||||
#define VERSION_WITH_PERIODS 8.26.25349.19000
|
||||
#define COPYRIGHT "Copyright (C) 1993-2025, Robert McNeel & Associates. All Rights Reserved."
|
||||
#define VERSION_WITH_COMMAS 8,29,26063,11000
|
||||
#define VERSION_WITH_PERIODS 8.29.26063.11000
|
||||
#define COPYRIGHT "Copyright (C) 1993-2026, Robert McNeel & Associates. All Rights Reserved."
|
||||
#define SPECIAL_BUILD_DESCRIPTION "Public OpenNURBS C++ 3dm file IO library."
|
||||
|
||||
#define RMA_VERSION_NUMBER_MAJOR_STRING "8"
|
||||
#define RMA_VERSION_NUMBER_MAJOR_WSTRING L"8"
|
||||
#define RMA_PREVIOUS_VERSION_NUMBER_MAJOR_WSTRING L"7"
|
||||
|
||||
#define RMA_VERSION_NUMBER_SR_STRING "SR26"
|
||||
#define RMA_VERSION_NUMBER_SR_WSTRING L"SR26"
|
||||
#define RMA_VERSION_NUMBER_SR_STRING "SR29"
|
||||
#define RMA_VERSION_NUMBER_SR_WSTRING L"SR29"
|
||||
|
||||
#define RMA_VERSION_WITH_PERIODS_STRING "8.26.25349.19000"
|
||||
#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.26.25349.19000"
|
||||
#define RMA_VERSION_WITH_PERIODS_STRING "8.29.26063.11000"
|
||||
#define RMA_VERSION_WITH_PERIODS_WSTRING L"8.29.26063.11000"
|
||||
|
||||
|
||||
|
||||
|
||||
@@ -621,7 +621,7 @@ bool ON_Quaternion::GetYawPitchRoll(double& yaw, double& pitch, double& roll) co
|
||||
ON_Xform X;
|
||||
bool rc = GetRotation(X);
|
||||
if (rc)
|
||||
rc = GetYawPitchRoll(yaw, pitch, roll);
|
||||
rc = X.GetYawPitchRoll(yaw, pitch, roll);
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -630,7 +630,7 @@ bool ON_Quaternion::GetEulerZYZ(double& alpha, double& beta, double& gamma) con
|
||||
ON_Xform X;
|
||||
bool rc = GetRotation(X);
|
||||
if (rc)
|
||||
rc = GetEulerZYZ(alpha, beta, gamma);
|
||||
rc = X.GetEulerZYZ(alpha, beta, gamma);
|
||||
return rc;
|
||||
|
||||
}
|
||||
|
||||
@@ -111,6 +111,7 @@ ON_SectionStyle& ON_SectionStyle::operator=(const ON_SectionStyle& other)
|
||||
}
|
||||
return *this;
|
||||
}
|
||||
|
||||
bool ON_SectionStyle::IsValid( ON_TextLog* text_log ) const
|
||||
{
|
||||
if (false == ON_ModelComponent::IsValid(text_log))
|
||||
@@ -134,6 +135,43 @@ bool ON_SectionStyle::IsValid( ON_TextLog* text_log ) const
|
||||
return true;
|
||||
}
|
||||
|
||||
const ON_SectionStyle* ON_SectionStyle::FromModelComponentRef(
|
||||
const class ON_ModelComponentReference& model_component_reference,
|
||||
const ON_SectionStyle* none_return_value
|
||||
)
|
||||
{
|
||||
const ON_SectionStyle* p = ON_SectionStyle::Cast(model_component_reference.ModelComponent());
|
||||
return (nullptr != p) ? p : none_return_value;
|
||||
}
|
||||
|
||||
bool ON_SectionStyle::UpdateReferencedComponents(
|
||||
const class ON_ComponentManifest& source_manifest,
|
||||
const class ON_ComponentManifest& destination_manifest,
|
||||
const class ON_ManifestMap& manifest_map
|
||||
)
|
||||
{
|
||||
bool rc = true;
|
||||
// Update hatch pattern index
|
||||
int hatch_index = HatchIndex();
|
||||
if (hatch_index >= 0)
|
||||
{
|
||||
int destination_hatch_index = -1;
|
||||
if (manifest_map.GetAndValidateDestinationIndex(ON_ModelComponent::Type::HatchPattern, hatch_index, destination_manifest, &destination_hatch_index))
|
||||
{
|
||||
hatch_index = destination_hatch_index;
|
||||
}
|
||||
else
|
||||
{
|
||||
ON_ERROR("Unable to update hatch pattern reference.");
|
||||
rc = false;
|
||||
hatch_index = DefaultSectionStylePrivate.m_hatch_index;
|
||||
}
|
||||
SetHatchIndex(hatch_index);
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
|
||||
// 12 Aug 2021 S. Baer
|
||||
// When adding new fields written to 3dm files, always add information to this
|
||||
// Dump function. Dump is used by the opennurbs file testing framework to
|
||||
|
||||
+32
-13
@@ -31,32 +31,52 @@ public:
|
||||
static const ON_SectionStyle Unset; // index = ON_UNSET_INT_INDEX, id = nil
|
||||
|
||||
/*
|
||||
Description:
|
||||
Tests that name is set and there is at least one non-zero length segment
|
||||
Parameters:
|
||||
model_component_reference - [in]
|
||||
none_return_value - [in]
|
||||
value to return if ON_SectionStyle::Cast(model_component_ref.ModelComponent())
|
||||
is nullptr
|
||||
Returns:
|
||||
If ON_SectionStyle::Cast(model_component_ref.ModelComponent()) is not nullptr,
|
||||
that pointer is returned. Otherwise, none_return_value is returned.
|
||||
*/
|
||||
static const ON_SectionStyle* FromModelComponentRef(
|
||||
const class ON_ModelComponentReference& model_component_reference,
|
||||
const ON_SectionStyle* none_return_value
|
||||
);
|
||||
|
||||
bool UpdateReferencedComponents(
|
||||
const class ON_ComponentManifest& source_manifest,
|
||||
const class ON_ComponentManifest& destination_manifest,
|
||||
const class ON_ManifestMap& manifest_map
|
||||
) override;
|
||||
|
||||
/*
|
||||
Description:
|
||||
Tests that name is set and there is at least one non-zero length segment
|
||||
*/
|
||||
bool IsValid( class ON_TextLog* text_log = nullptr ) const override;
|
||||
|
||||
void Dump( ON_TextLog& ) const override; // for debugging
|
||||
|
||||
/*
|
||||
Description:
|
||||
Write to file (serialize definition to binary archive)
|
||||
Description:
|
||||
Write to file (serialize definition to binary archive)
|
||||
*/
|
||||
bool Write(ON_BinaryArchive&) const override;
|
||||
|
||||
/*
|
||||
Description:
|
||||
Read from file (restore definition from binary archive)
|
||||
Description:
|
||||
Read from file (restore definition from binary archive)
|
||||
*/
|
||||
bool Read(ON_BinaryArchive&) override;
|
||||
|
||||
|
||||
/*
|
||||
Description:
|
||||
Test only the section style attributes below for equality. Does not
|
||||
perform any testing of the ON_ModelComponent fields
|
||||
Parameters:
|
||||
other: other section style to compare against this
|
||||
Description:
|
||||
Test only the section style attributes below for equality. Does not
|
||||
perform any testing of the ON_ModelComponent fields
|
||||
Parameters:
|
||||
other: other section style to compare against this
|
||||
*/
|
||||
bool SectionAttributesEqual(const ON_SectionStyle& other) const;
|
||||
|
||||
@@ -89,7 +109,6 @@ public:
|
||||
SectionBackgroundFillMode BackgroundFillMode() const;
|
||||
void SetBackgroundFillMode(SectionBackgroundFillMode mode);
|
||||
|
||||
|
||||
// Custom background fill color. If unset (default), the object's color or
|
||||
// material is used for a fill
|
||||
ON_Color BackgroundFillColor(bool print) const;
|
||||
|
||||
@@ -46,6 +46,7 @@ enum class ON_SubDGetControlNetMeshPriority : unsigned char
|
||||
};
|
||||
|
||||
|
||||
#pragma region RH_C_SHARED_ENUM [ON_SubDTextureCoordinateType] [Rhino.Geometry.SubDTextureCoordinateType] [byte]
|
||||
/// <summary>
|
||||
/// ON_SubDTextureCoordinateType identifies the way ON_SubDMeshFragment texture coordinates are set from an ON_SubDFace.
|
||||
/// </summary>
|
||||
@@ -91,6 +92,7 @@ enum class ON_SubDTextureCoordinateType : unsigned char
|
||||
///</summary>
|
||||
FromMapping = 7,
|
||||
};
|
||||
#pragma endregion
|
||||
|
||||
#pragma region RH_C_SHARED_ENUM [ON_SubDVertexTag] [Rhino.Geometry.SubDVertexTag] [byte]
|
||||
/// <summary>
|
||||
|
||||
+64
-4
@@ -537,6 +537,14 @@ const ON_wString ON_TextContent::Internal_GetPlainText(bool evaluate_fields, boo
|
||||
map.j = plaintext.Length();
|
||||
map.k = (int)wcslen(str);
|
||||
}
|
||||
|
||||
// December 3, 2025 - Tim
|
||||
// Fix for https://mcneel.myjetbrains.com/youtrack/issue/RH-90830
|
||||
// Add a space before the fraction if is not the first
|
||||
// chunk of text.
|
||||
if (0 < ri && nullptr != wcschr(str, '/'))
|
||||
plaintext += " ";
|
||||
|
||||
plaintext += str;
|
||||
}
|
||||
}
|
||||
@@ -2524,9 +2532,22 @@ bool ON_TextContent::FormatLength(
|
||||
wchar_t decimal_char,
|
||||
ON_wString & output)
|
||||
{
|
||||
// Record length before appending so we only replace periods in the newly added portion
|
||||
const int length_before = output.Length();
|
||||
bool rc = ON_NumberFormatter::FormatLength( distance, output_lengthdisplay, round_off, resolution, zero_suppress, bracket_fractions, output);
|
||||
if (rc && ON_wString::DecimalAsPeriod != decimal_char)
|
||||
output.Replace(ON_wString::DecimalAsPeriod, decimal_char);
|
||||
{
|
||||
// Only replace periods in the newly appended portion, not in any pre-existing text RH-83506
|
||||
wchar_t* str = output.Array();
|
||||
if (nullptr != str)
|
||||
{
|
||||
for (int i = length_before; i < output.Length(); i++)
|
||||
{
|
||||
if (str[i] == ON_wString::DecimalAsPeriod)
|
||||
str[i] = decimal_char;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2544,9 +2565,22 @@ bool ON_TextContent::FormatAngleStringDMS(
|
||||
int resolution,
|
||||
ON_wString& formatted_string)
|
||||
{
|
||||
// Record length before appending so we only replace periods in the newly added portion
|
||||
const int length_before = formatted_string.Length();
|
||||
bool rc = ON_NumberFormatter::FormatAngleStringDMS(angle_degrees, resolution, formatted_string);
|
||||
if (rc && ON_wString::DecimalAsPeriod != decimal_char)
|
||||
formatted_string.Replace(ON_wString::DecimalAsPeriod, decimal_char);
|
||||
{
|
||||
// Only replace periods in the newly appended portion, not in any pre-existing text RH-83506
|
||||
wchar_t* str = formatted_string.Array();
|
||||
if (nullptr != str)
|
||||
{
|
||||
for (int i = length_before; i < formatted_string.Length(); i++)
|
||||
{
|
||||
if (str[i] == ON_wString::DecimalAsPeriod)
|
||||
str[i] = decimal_char;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2558,9 +2592,22 @@ bool ON_TextContent::FormatAngleStringDecimal(
|
||||
wchar_t decimal_char,
|
||||
ON_wString& formatted_string)
|
||||
{
|
||||
// Record length before appending so we only replace periods in the newly added portion
|
||||
const int length_before = formatted_string.Length();
|
||||
bool rc = ON_NumberFormatter::FormatAngleStringDecimal(angle_radians, resolution, roundoff, zero_suppression, formatted_string);
|
||||
if (rc && ON_wString::DecimalAsPeriod != decimal_char)
|
||||
formatted_string.Replace(ON_wString::DecimalAsPeriod, decimal_char);
|
||||
{
|
||||
// Only replace periods in the newly appended portion, not in any pre-existing text RH-83506
|
||||
wchar_t* str = formatted_string.Array();
|
||||
if (nullptr != str)
|
||||
{
|
||||
for (int i = length_before; i < formatted_string.Length(); i++)
|
||||
{
|
||||
if (str[i] == ON_wString::DecimalAsPeriod)
|
||||
str[i] = decimal_char;
|
||||
}
|
||||
}
|
||||
}
|
||||
return rc;
|
||||
}
|
||||
|
||||
@@ -2623,6 +2670,8 @@ bool ON_TextContent::FormatAreaOrVolume(
|
||||
|
||||
ON_DimStyle::OBSOLETE_length_format output_format = ON_DimStyle::OBSOLETE_length_format::Decimal;
|
||||
|
||||
// Record length before appending so we only replace periods in the newly added portion
|
||||
const int length_before = formatted_string.Length();
|
||||
bool rc = ON_NumberFormatter::FormatNumber(
|
||||
value,
|
||||
output_format,
|
||||
@@ -2633,7 +2682,18 @@ bool ON_TextContent::FormatAreaOrVolume(
|
||||
formatted_string);
|
||||
|
||||
if (rc && ON_wString::DecimalAsPeriod != decimal_char)
|
||||
formatted_string.Replace(ON_wString::DecimalAsPeriod, decimal_char);
|
||||
{
|
||||
// Only replace periods in the newly appended portion, not in any pre-existing text RH-83506
|
||||
wchar_t* str = formatted_string.Array();
|
||||
if (nullptr != str)
|
||||
{
|
||||
for (int i = length_before; i < formatted_string.Length(); i++)
|
||||
{
|
||||
if (str[i] == ON_wString::DecimalAsPeriod)
|
||||
str[i] = decimal_char;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
return rc;
|
||||
}
|
||||
|
||||
+246
-200
@@ -1048,6 +1048,250 @@ void ON_TextRun::SetUnicodeString(ON__UINT32*& dest, size_t count, const ON__UIN
|
||||
}
|
||||
}
|
||||
|
||||
// 2026-02-10 - kike@mcneel.com : See RH-91129
|
||||
// ON_TextRun::WrapTextRun should be iterative instead of recursive.
|
||||
// But by now and to fix the issue the recursion level is now 128
|
||||
// And the recursive function ON_TextWrapper::WrapTextRun is lighter on stack than before.
|
||||
// Also the glyph extraction is done just once, so should be faster than before.
|
||||
class ON_TextWrapper
|
||||
{
|
||||
const int max_recursion_level = 128;
|
||||
|
||||
const ON_TextRun& text_run;
|
||||
ON_TextRunArray& newruns;
|
||||
const wchar_t* display_string;
|
||||
const size_t wcscount;
|
||||
|
||||
const ON_Font* font;
|
||||
double height_scale;
|
||||
ON_SimpleArray<const ON_FontGlyph*> glyph_list;
|
||||
ON_TextBox text_box;
|
||||
|
||||
public:
|
||||
ON_TextWrapper(const ON_TextRun& run, ON_TextRunArray& runs) :
|
||||
text_run(run),
|
||||
newruns(runs),
|
||||
display_string(run.DisplayString()),
|
||||
wcscount(nullptr != display_string ? wcslen(display_string) : 0)
|
||||
{ }
|
||||
|
||||
int WrapText(
|
||||
int call_count, // recursion depth
|
||||
int start_char_offset, // char offset in cp array
|
||||
double wrapwidth, // max linewidth
|
||||
double& y_offset, // y offset from input run from previously added soft returns
|
||||
double& linewidth // linewidth so far
|
||||
)
|
||||
{
|
||||
font = text_run.Font();
|
||||
if (nullptr == font)
|
||||
return 0;
|
||||
|
||||
height_scale = text_run.HeightScale(font); // Font units to world units
|
||||
ON_FontGlyph::GetGlyphList(display_string, font, ON_NextLine, glyph_list, text_box);
|
||||
{
|
||||
const ON_FontGlyph* Aglyph = font->CodePointGlyph((ON__UINT32)L'A');
|
||||
if (nullptr == Aglyph)
|
||||
return 0;
|
||||
|
||||
const ON_TextBox& Aglyph_box = Aglyph->GlyphBox();
|
||||
double Awidth = Aglyph_box.m_advance.i * height_scale;
|
||||
// height scale is ~1e-3 so floor() will pretty much always make this value 0
|
||||
// when text height is much less than 1, so this is a test for a NAN result
|
||||
if (floor(Awidth) < 0.0)
|
||||
{
|
||||
ON_ERROR("Font height scale * width of 'A' is less than 0\n");
|
||||
return 0;
|
||||
}
|
||||
if (!(Awidth > 0.0 && wrapwidth >= Awidth))
|
||||
return 0;
|
||||
}
|
||||
|
||||
return WrapTextRun(call_count, start_char_offset, wrapwidth, y_offset, linewidth);
|
||||
}
|
||||
|
||||
private:
|
||||
int WrapTextRun(
|
||||
int call_count, // recursion depth
|
||||
int start_char_offset, // char offset in cp array
|
||||
double wrapwidth, // max linewidth
|
||||
double& y_offset, // y offset from input run from previously added soft returns
|
||||
double& linewidth // linewidth so far
|
||||
)
|
||||
{
|
||||
int new_count = 0;
|
||||
|
||||
if (max_recursion_level < call_count)
|
||||
{
|
||||
ON_ERROR("WrapTextRun: Recursion too deep.");
|
||||
return 0;
|
||||
}
|
||||
if (0 > start_char_offset)
|
||||
{
|
||||
ON_ERROR("WrapTextRun: String start offset < 0.");
|
||||
start_char_offset = 0;
|
||||
}
|
||||
if (0.0 > linewidth)
|
||||
{
|
||||
ON_ERROR("WrapTextRun: Linewidtht < 0.");
|
||||
linewidth = 0.0;
|
||||
}
|
||||
|
||||
wchar_t* temp_display_str = (wchar_t*)onmalloc((wcscount + 1) * sizeof(wchar_t));
|
||||
double runwidth = 0.0; // run width without trailing spaces
|
||||
{
|
||||
#pragma region Run Width
|
||||
//double runwidth0 = 0.0; // run width including trailing spaces
|
||||
if (0 == start_char_offset) // using the whole run
|
||||
{
|
||||
//runwidth = Advance().x;
|
||||
runwidth = text_box.m_advance.i * height_scale;
|
||||
}
|
||||
else // Part of the run has already been picked off and added to the previous line
|
||||
{
|
||||
// Find width of remaining characters
|
||||
for (int ci = start_char_offset; ci < wcscount && ci < glyph_list.Count(); ci++)
|
||||
{
|
||||
const ON_FontGlyph* gi = glyph_list[ci];
|
||||
|
||||
if (nullptr != gi)
|
||||
{
|
||||
const ON_TextBox& glyph_box = gi->GlyphBox();
|
||||
double charwidth = glyph_box.m_advance.i * height_scale;
|
||||
runwidth += charwidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0.0 > runwidth)
|
||||
runwidth = 0.0;
|
||||
#pragma endregion Run Width
|
||||
|
||||
#pragma region Whole Run
|
||||
if (runwidth + linewidth <= wrapwidth || 2 > wcscount)
|
||||
{
|
||||
// Adding this entire run won't go past wrap width
|
||||
// or the run has only 0 or 1 character and can't be wrapped
|
||||
ON_TextRun* newrun = ON_TextRun::GetManagedTextRun();
|
||||
if (nullptr != newrun)
|
||||
{
|
||||
*newrun = text_run;
|
||||
if (text_run.Type() == ON_TextRun::RunType::kNewline ||
|
||||
text_run.Type() == ON_TextRun::RunType::kParagraph ||
|
||||
text_run.Type() == ON_TextRun::RunType::kSoftreturn)
|
||||
linewidth = 0.0;
|
||||
else
|
||||
{
|
||||
if (0 != start_char_offset)
|
||||
{
|
||||
wcsncpy(temp_display_str, display_string + start_char_offset, wcscount - start_char_offset);
|
||||
temp_display_str[wcscount - start_char_offset] = 0;
|
||||
newrun->SetDisplayString(temp_display_str);
|
||||
}
|
||||
linewidth += runwidth;
|
||||
}
|
||||
newruns.AppendRun(newrun);
|
||||
onfree(temp_display_str);
|
||||
return 1; // 1 new run was added
|
||||
}
|
||||
}
|
||||
#pragma endregion Whole Run
|
||||
}
|
||||
|
||||
// Find what part of the run will fit
|
||||
bool found_space = false;
|
||||
int last_space = -1;
|
||||
int run_length = 0;
|
||||
double curwidth = 0.0;
|
||||
double linefeedheight = font->FontMetrics().LineSpace() * height_scale;
|
||||
|
||||
int sp_count = 0;
|
||||
for (int ci = start_char_offset; ci < (int)wcscount; ci++)
|
||||
{
|
||||
if ((ci + 1) < wcscount &&
|
||||
display_string[ci] >= 0xD800 && display_string[ci] < 0xDC00 &&
|
||||
display_string[ci + 1] >= 0xDC00 && display_string[ci + 1] < 0xE000)
|
||||
{
|
||||
sp_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int gi = ci - sp_count;
|
||||
if (gi >= glyph_list.Count())
|
||||
break;
|
||||
|
||||
const ON_FontGlyph* glyph = glyph_list[gi];
|
||||
if (nullptr != glyph)
|
||||
{
|
||||
const ON_TextBox& glyph_box = glyph->GlyphBox();
|
||||
curwidth += glyph_box.m_advance.i * height_scale;
|
||||
run_length++;
|
||||
|
||||
if (linewidth + curwidth > wrapwidth) // reached wrapping width
|
||||
{
|
||||
if (found_space) // store run up to last space
|
||||
run_length = last_space - start_char_offset + 1;
|
||||
else if (0.0 < linewidth) // A line is already started
|
||||
run_length = 0;
|
||||
else // no space yet - store run up to this char position
|
||||
run_length = ci - start_char_offset;
|
||||
|
||||
if (0 < run_length)
|
||||
{
|
||||
ON_TextRun* newrun = ON_TextRun::GetManagedTextRun(); // make a new run
|
||||
if (nullptr != newrun)
|
||||
{
|
||||
*newrun = text_run;
|
||||
wcsncpy(temp_display_str, display_string + start_char_offset, run_length);
|
||||
temp_display_str[run_length] = 0;
|
||||
newrun->SetDisplayString(temp_display_str);
|
||||
newrun->SetOffset(ON_2dVector(0.0, y_offset + text_run.Offset().y));
|
||||
newruns.AppendRun(newrun);
|
||||
}
|
||||
}
|
||||
// add a soft return
|
||||
ON_TextRun* lfrun = ON_TextRun::GetManagedTextRun();
|
||||
if (nullptr != lfrun)
|
||||
{
|
||||
lfrun->SetFont(font);
|
||||
lfrun->SetType(ON_TextRun::RunType::kSoftreturn);
|
||||
lfrun->SetTextHeight(text_run.TextHeight());
|
||||
newruns.AppendRun(lfrun);
|
||||
|
||||
// Starting a new line now
|
||||
linewidth = 0.0;
|
||||
curwidth = 0.0;
|
||||
y_offset -= linefeedheight;
|
||||
}
|
||||
|
||||
int wrapcount = WrapTextRun(call_count + 1, run_length + start_char_offset, wrapwidth, y_offset, linewidth);
|
||||
|
||||
onfree(temp_display_str);
|
||||
return new_count + wrapcount;
|
||||
}
|
||||
if (iswspace(display_string[ci]))
|
||||
{
|
||||
found_space = true;
|
||||
last_space = ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ON_TextRun* newrun = ON_TextRun::GetManagedTextRun(); // make a new run
|
||||
if (nullptr != newrun)
|
||||
{
|
||||
*newrun = text_run;
|
||||
wcsncpy(temp_display_str, display_string + start_char_offset, run_length);
|
||||
temp_display_str[run_length] = 0;
|
||||
newrun->SetOffset(ON_2dVector(0.0, y_offset + text_run.Offset().y));
|
||||
newruns.AppendRun(newrun);
|
||||
new_count += 1;
|
||||
}
|
||||
onfree(temp_display_str);
|
||||
return new_count;
|
||||
}
|
||||
};
|
||||
|
||||
int ON_TextRun::WrapTextRun(
|
||||
int call_count, // recursion depth
|
||||
int start_char_offset, // char offset in cp array
|
||||
@@ -1057,206 +1301,8 @@ int ON_TextRun::WrapTextRun(
|
||||
ON_TextRunArray& newruns// new runs made by wrapping
|
||||
) const
|
||||
{
|
||||
int new_count = 0;
|
||||
|
||||
if (500 < call_count)
|
||||
{
|
||||
ON_ERROR("WrapTextRun: Recursion too deep.");
|
||||
return 0;
|
||||
}
|
||||
if (0 > start_char_offset)
|
||||
{
|
||||
ON_ERROR("WrapTextRun: String start offset < 0.");
|
||||
start_char_offset = 0;
|
||||
}
|
||||
|
||||
if (0.0 > linewidth)
|
||||
{
|
||||
ON_ERROR("WrapTextRun: Linewidtht < 0.");
|
||||
linewidth = 0.0;
|
||||
}
|
||||
|
||||
const wchar_t* display_string = DisplayString();
|
||||
|
||||
size_t wcscount = 0;
|
||||
if (nullptr != display_string)
|
||||
wcscount = wcslen(display_string);
|
||||
|
||||
const ON_Font* font = Font();
|
||||
if (nullptr == font)
|
||||
return 0;
|
||||
double height_scale = HeightScale(font); // Font units to world units
|
||||
|
||||
ON_SimpleArray< const ON_FontGlyph*> glyph_list;
|
||||
ON_TextBox text_box;
|
||||
|
||||
ON_FontGlyph::GetGlyphList(display_string, font, ON_NextLine, glyph_list, text_box);
|
||||
int glyph_count = glyph_list.Count();
|
||||
|
||||
const ON_FontGlyph* Aglyph = font->CodePointGlyph((ON__UINT32)L'A');
|
||||
if (nullptr == Aglyph)
|
||||
return 0;
|
||||
const ON_TextBox Aglyph_box = Aglyph->GlyphBox();
|
||||
double Awidth = Aglyph_box.m_advance.i * height_scale;
|
||||
// height scale is ~1e-3 so floor() will pretty much always make this value 0
|
||||
// when text height is much less than 1, so this is a test for a NAN result
|
||||
if (floor(Awidth) < 0.0)
|
||||
{
|
||||
ON_ERROR("Font height scale * width of 'A' is less than 0\n");
|
||||
return 0;
|
||||
}
|
||||
if (!(Awidth > 0.0 && wrapwidth >= Awidth))
|
||||
return 0;
|
||||
|
||||
#pragma region Run Width
|
||||
double runwidth = 0.0; // run width without trailing spaces
|
||||
//double runwidth0 = 0.0; // run width including trailing spaces
|
||||
if (0 == start_char_offset) // using the whole run
|
||||
{
|
||||
//runwidth = Advance().x;
|
||||
runwidth = text_box.m_advance.i * height_scale;
|
||||
}
|
||||
else // Part of the run has already been picked off and added to the previous line
|
||||
{
|
||||
// Find width of remaining characters
|
||||
for (int ci = start_char_offset; ci < wcscount && ci < glyph_count; ci++)
|
||||
{
|
||||
const ON_FontGlyph* gi = glyph_list[ci];
|
||||
|
||||
if (nullptr != gi)
|
||||
{
|
||||
const ON_TextBox glyph_box = gi->GlyphBox();
|
||||
double charwidth = glyph_box.m_advance.i * height_scale;
|
||||
runwidth += charwidth;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
if (0.0 > runwidth)
|
||||
runwidth = 0.0;
|
||||
#pragma endregion Run Width
|
||||
|
||||
#pragma region Whole Run
|
||||
wchar_t* temp_display_str = (wchar_t*)onmalloc((wcscount + 1) * sizeof(wchar_t));
|
||||
if (runwidth + linewidth <= wrapwidth || 2 > wcscount)
|
||||
{
|
||||
// Adding this entire run won't go past wrap width
|
||||
// or the run has only 0 or 1 character and can't be wrapped
|
||||
ON_TextRun* newrun = ON_TextRun::GetManagedTextRun();
|
||||
if (nullptr != newrun)
|
||||
{
|
||||
*newrun = *this;
|
||||
if (Type() == ON_TextRun::RunType::kNewline ||
|
||||
Type() == ON_TextRun::RunType::kParagraph ||
|
||||
Type() == ON_TextRun::RunType::kSoftreturn)
|
||||
linewidth = 0.0;
|
||||
else
|
||||
{
|
||||
if (0 != start_char_offset)
|
||||
{
|
||||
wcsncpy(temp_display_str, display_string + start_char_offset, wcscount - start_char_offset);
|
||||
temp_display_str[wcscount - start_char_offset] = 0;
|
||||
newrun->SetDisplayString(temp_display_str);
|
||||
}
|
||||
linewidth += runwidth;
|
||||
}
|
||||
newruns.AppendRun(newrun);
|
||||
onfree(temp_display_str);
|
||||
return 1; // 1 new run was added
|
||||
}
|
||||
}
|
||||
#pragma endregion Whole Run
|
||||
|
||||
// Find what part of the run will fit
|
||||
bool found_space = false;
|
||||
int last_space = -1;
|
||||
int run_length = 0;
|
||||
double curwidth = 0.0;
|
||||
double linefeedheight = font->FontMetrics().LineSpace() * height_scale;
|
||||
|
||||
int sp_count = 0;
|
||||
for (int ci = start_char_offset; ci < (int)wcscount; ci++)
|
||||
{
|
||||
if ((ci + 1) < wcscount &&
|
||||
display_string[ci] >= 0xD800 && display_string[ci] < 0xDC00 &&
|
||||
display_string[ci + 1] >= 0xDC00 && display_string[ci + 1] < 0xE000)
|
||||
{
|
||||
sp_count++;
|
||||
continue;
|
||||
}
|
||||
|
||||
int gi = ci - sp_count;
|
||||
if (gi >= glyph_count)
|
||||
break;
|
||||
|
||||
const ON_FontGlyph* glyph = glyph_list[gi];
|
||||
if (nullptr != glyph)
|
||||
{
|
||||
const ON_TextBox glyph_box = glyph->GlyphBox();
|
||||
curwidth += glyph_box.m_advance.i * height_scale;
|
||||
run_length++;
|
||||
|
||||
if (linewidth + curwidth > wrapwidth) // reached wrapping width
|
||||
{
|
||||
if (found_space) // store run up to last space
|
||||
run_length = last_space - start_char_offset + 1;
|
||||
else if (0.0 < linewidth) // A line is already started
|
||||
run_length = 0;
|
||||
else // no space yet - store run up to this char position
|
||||
run_length = ci - start_char_offset;
|
||||
|
||||
if (0 < run_length)
|
||||
{
|
||||
ON_TextRun* newrun = ON_TextRun::GetManagedTextRun(); // make a new run
|
||||
if (nullptr != newrun)
|
||||
{
|
||||
*newrun = *this;
|
||||
wcsncpy(temp_display_str, display_string + start_char_offset, run_length);
|
||||
temp_display_str[run_length] = 0;
|
||||
newrun->SetDisplayString(temp_display_str);
|
||||
newrun->SetOffset(ON_2dVector(0.0, y_offset + Offset().y));
|
||||
newruns.AppendRun(newrun);
|
||||
}
|
||||
}
|
||||
// add a soft return
|
||||
ON_TextRun* lfrun = ON_TextRun::GetManagedTextRun();
|
||||
if (nullptr != lfrun)
|
||||
{
|
||||
lfrun->SetFont(Font());
|
||||
lfrun->SetType(ON_TextRun::RunType::kSoftreturn);
|
||||
lfrun->SetTextHeight(this->TextHeight());
|
||||
newruns.AppendRun(lfrun);
|
||||
|
||||
// Starting a new line now
|
||||
linewidth = 0.0;
|
||||
curwidth = 0.0;
|
||||
y_offset -= linefeedheight;
|
||||
}
|
||||
|
||||
int wrapcount = WrapTextRun(call_count + 1, run_length + start_char_offset, wrapwidth, y_offset, linewidth, newruns);
|
||||
onfree(temp_display_str);
|
||||
return new_count + wrapcount;
|
||||
}
|
||||
if (iswspace(display_string[ci]))
|
||||
{
|
||||
found_space = true;
|
||||
last_space = ci;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
ON_TextRun* newrun = ON_TextRun::GetManagedTextRun(); // make a new run
|
||||
if (nullptr != newrun)
|
||||
{
|
||||
*newrun = *this;
|
||||
wcsncpy(temp_display_str, display_string + start_char_offset, run_length);
|
||||
temp_display_str[run_length] = 0;
|
||||
newrun->SetOffset(ON_2dVector(0.0, y_offset + Offset().y));
|
||||
newruns.AppendRun(newrun);
|
||||
new_count += 1;
|
||||
}
|
||||
onfree(temp_display_str);
|
||||
return new_count;
|
||||
ON_TextWrapper wrapper(*this, newruns);
|
||||
return wrapper.WrapText(call_count, start_char_offset, wrapwidth, y_offset, linewidth);
|
||||
}
|
||||
|
||||
ON_StackedText::StackStyle ON_StackedText::StackStyleFromUnsigned(
|
||||
|
||||
Reference in New Issue
Block a user