2021-12-31 14:07:24 +00:00
|
|
|
/*
|
|
|
|
* This program source code file is part of KiCad, a free EDA CAD application.
|
|
|
|
*
|
|
|
|
* Copyright (C) 2021 Ola Rinta-Koski <gitlab@rinta-koski.net>
|
2024-01-12 17:04:05 +00:00
|
|
|
* Copyright (C) 2021-2024 KiCad Developers, see AUTHORS.txt for contributors.
|
2021-12-31 14:07:24 +00:00
|
|
|
*
|
|
|
|
* This program is free software: you can redistribute it and/or modify it
|
|
|
|
* under the terms of the GNU General Public License as published by the
|
|
|
|
* Free Software Foundation, either version 3 of the License, or (at your
|
|
|
|
* option) any later version.
|
|
|
|
*
|
|
|
|
* This program is distributed in the hope that it will be useful, but
|
|
|
|
* WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU General Public License along
|
|
|
|
* with this program. If not, see <http://www.gnu.org/licenses/>.
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <vector>
|
|
|
|
#include <font/glyph.h>
|
2022-01-04 23:00:00 +00:00
|
|
|
#include <trigo.h>
|
2021-12-31 14:07:24 +00:00
|
|
|
|
|
|
|
using namespace KIFONT;
|
|
|
|
|
|
|
|
|
|
|
|
STROKE_GLYPH::STROKE_GLYPH( const STROKE_GLYPH& aGlyph )
|
|
|
|
{
|
2022-09-14 16:07:47 +00:00
|
|
|
reserve( aGlyph.size() );
|
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
for( const std::vector<VECTOR2D>& pointList : aGlyph )
|
|
|
|
push_back( pointList );
|
|
|
|
|
|
|
|
m_boundingBox = aGlyph.m_boundingBox;
|
2021-12-31 14:07:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void STROKE_GLYPH::AddPoint( const VECTOR2D& aPoint )
|
|
|
|
{
|
|
|
|
if( !m_penIsDown )
|
|
|
|
{
|
2022-01-09 14:28:07 +00:00
|
|
|
emplace_back();
|
|
|
|
back().reserve( 16 ); // This handles all but 359 strokes (out of over 328,000)
|
2021-12-31 14:07:24 +00:00
|
|
|
m_penIsDown = true;
|
|
|
|
}
|
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
back().push_back( aPoint );
|
2021-12-31 14:07:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void STROKE_GLYPH::RaisePen()
|
|
|
|
{
|
2022-01-09 14:28:07 +00:00
|
|
|
#if 0
|
2021-12-31 14:07:24 +00:00
|
|
|
if( m_penIsDown )
|
2022-01-04 00:44:59 +00:00
|
|
|
back().shrink_to_fit();
|
2022-01-09 14:28:07 +00:00
|
|
|
#endif
|
2021-12-31 14:07:24 +00:00
|
|
|
|
|
|
|
m_penIsDown = false;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void STROKE_GLYPH::Finalize()
|
|
|
|
{
|
2022-01-09 14:28:07 +00:00
|
|
|
// Shrinking the strokes saves a bit less than 512K of memory. It's not worth it for the
|
|
|
|
// performance hit of doing more than 328,000 reallocs.
|
|
|
|
#if 0
|
|
|
|
if( !empty() && !back().empty() )
|
2022-01-04 00:44:59 +00:00
|
|
|
back().shrink_to_fit();
|
2022-01-09 14:28:07 +00:00
|
|
|
#endif
|
2021-12-31 14:07:24 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-04 23:00:00 +00:00
|
|
|
std::unique_ptr<GLYPH> STROKE_GLYPH::Transform( const VECTOR2D& aGlyphSize, const VECTOR2I& aOffset,
|
|
|
|
double aTilt, const EDA_ANGLE& aAngle, bool aMirror,
|
|
|
|
const VECTOR2I& aOrigin )
|
2021-12-31 14:07:24 +00:00
|
|
|
{
|
2022-01-04 00:44:59 +00:00
|
|
|
std::unique_ptr<STROKE_GLYPH> glyph = std::make_unique<STROKE_GLYPH>( *this );
|
2021-12-31 14:07:24 +00:00
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
VECTOR2D end = glyph->m_boundingBox.GetEnd();
|
2021-12-31 14:07:24 +00:00
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
end.x *= aGlyphSize.x;
|
|
|
|
end.y *= aGlyphSize.y;
|
2021-12-31 14:07:24 +00:00
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
if( aTilt )
|
|
|
|
end.x -= end.y * aTilt;
|
2021-12-31 14:07:24 +00:00
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
glyph->m_boundingBox.SetEnd( end );
|
|
|
|
glyph->m_boundingBox.Offset( aOffset );
|
2021-12-31 14:07:24 +00:00
|
|
|
|
2022-01-04 00:44:59 +00:00
|
|
|
for( std::vector<VECTOR2D>& pointList : *glyph.get() )
|
2021-12-31 14:07:24 +00:00
|
|
|
{
|
|
|
|
for( VECTOR2D& point : pointList )
|
|
|
|
{
|
2022-01-04 23:00:00 +00:00
|
|
|
point *= aGlyphSize;
|
2021-12-31 14:07:24 +00:00
|
|
|
|
|
|
|
if( aTilt )
|
|
|
|
point.x -= point.y * aTilt;
|
|
|
|
|
2022-01-04 23:00:00 +00:00
|
|
|
point += aOffset;
|
|
|
|
|
|
|
|
if( aMirror )
|
|
|
|
point.x = aOrigin.x - ( point.x - aOrigin.x );
|
|
|
|
|
|
|
|
if( !aAngle.IsZero() )
|
|
|
|
RotatePoint( point, aOrigin, aAngle );
|
2021-12-31 14:07:24 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
return glyph;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2022-01-01 01:21:03 +00:00
|
|
|
BOX2D OUTLINE_GLYPH::BoundingBox()
|
|
|
|
{
|
|
|
|
BOX2I bbox = BBox();
|
|
|
|
return BOX2D( bbox.GetOrigin(), bbox.GetSize() );
|
|
|
|
}
|
2022-01-07 17:42:43 +00:00
|
|
|
|
|
|
|
|
2022-01-10 01:53:01 +00:00
|
|
|
void OUTLINE_GLYPH::Triangulate( std::function<void( const VECTOR2I& aPt1,
|
|
|
|
const VECTOR2I& aPt2,
|
|
|
|
const VECTOR2I& aPt3 )> aCallback ) const
|
2022-01-07 17:42:43 +00:00
|
|
|
{
|
2024-01-12 17:04:05 +00:00
|
|
|
const_cast<OUTLINE_GLYPH*>( this )->CacheTriangulation( false );
|
2022-01-07 17:42:43 +00:00
|
|
|
|
|
|
|
for( unsigned int i = 0; i < TriangulatedPolyCount(); i++ )
|
|
|
|
{
|
|
|
|
const SHAPE_POLY_SET::TRIANGULATED_POLYGON* polygon = TriangulatedPolygon( i );
|
|
|
|
|
2022-05-13 21:36:20 +00:00
|
|
|
for( size_t j = 0; j < polygon->GetTriangleCount(); j++ )
|
2022-01-07 17:42:43 +00:00
|
|
|
{
|
|
|
|
VECTOR2I a, b, c;
|
|
|
|
polygon->GetTriangle( j, a, b, c );
|
2022-01-10 01:53:01 +00:00
|
|
|
aCallback( a, b, c );
|
2022-01-07 17:42:43 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2024-01-12 17:04:05 +00:00
|
|
|
void OUTLINE_GLYPH::CacheTriangulation( bool aPartition, bool aSimplify )
|
|
|
|
{
|
|
|
|
// Only call CacheTriangulation if it has never been done before. Otherwise we'll hash
|
|
|
|
// the triangulation to see if it has been edited, and glyphs are invariant after creation.
|
|
|
|
//
|
|
|
|
// Also forces "partition" to false as we never want to partition a glyph.
|
|
|
|
|
|
|
|
if( TriangulatedPolyCount() == 0 )
|
|
|
|
SHAPE_POLY_SET::CacheTriangulation( false, aSimplify );
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>> OUTLINE_GLYPH::GetTriangulationData() const
|
|
|
|
{
|
|
|
|
std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>> data;
|
|
|
|
|
|
|
|
for( const std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>& poly : m_triangulatedPolys )
|
|
|
|
data.push_back( std::make_unique<SHAPE_POLY_SET::TRIANGULATED_POLYGON>( *poly ) );
|
|
|
|
|
|
|
|
return data;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
void OUTLINE_GLYPH::CacheTriangulation( std::vector<std::unique_ptr<SHAPE_POLY_SET::TRIANGULATED_POLYGON>>& aHintData )
|
|
|
|
{
|
|
|
|
cacheTriangulation( false, false, &aHintData );
|
|
|
|
}
|