/* * This program source code file is part of KiCad, a free EDA CAD application. * * Copyright (C) 2016-2020 CERN * Copyright (C) 2021-2022 KiCad Developers, see AUTHORS.txt for contributors. * * 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 2 * 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, you may find one here: * http://www.gnu.org/licenses/old-licenses/gpl-2.0.html * or you may search the http://www.gnu.org website for the version 2 license, * or you may write to the Free Software Foundation, Inc., * 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA */ #ifndef __SHAPE_COMPOUND_H #define __SHAPE_COMPOUND_H #include #include #include #include #include #include #include "eda_angle.h" class SHAPE_SIMPLE; class SHAPE_COMPOUND : public SHAPE { public: SHAPE_COMPOUND() : SHAPE( SH_COMPOUND ), m_dirty( true ) { } SHAPE_COMPOUND( const std::vector& aShapes ); SHAPE_COMPOUND( const SHAPE_COMPOUND& aOther ); ~SHAPE_COMPOUND(); SHAPE_COMPOUND* Clone() const override; const std::string Format( bool aCplusPlus = true ) const override; bool Collide( const SEG& aSeg, int aClearance = 0, int* aActual = nullptr, VECTOR2I* aLocation = nullptr ) const override; bool Collide( const SHAPE* aShape, int aClearance, VECTOR2I* aMTV ) const override { return SHAPE::Collide( aShape, aClearance, aMTV ); } bool Collide( const SHAPE* aShape, int aClearance = 0, int* aActual = nullptr, VECTOR2I* aLocation = nullptr ) const override { return SHAPE::Collide( aShape, aClearance, aActual, aLocation ); } const std::vector& Shapes() const { return m_shapes; } const BOX2I BBox( int aClearance = 0 ) const override; using SHAPE::Distance; int Distance( const SEG& aSeg ) const; void Move( const VECTOR2I& aVector ) override; void AddShape( SHAPE* aShape ) { // Don't make clients deal with nested SHAPE_COMPOUNDs if( dynamic_cast( aShape ) ) { std::vector subshapes; aShape->GetIndexableSubshapes( subshapes ); for( const SHAPE* subshape : subshapes ) m_shapes.push_back( subshape->Clone() ); delete aShape; } else { m_shapes.push_back( aShape ); } m_dirty = true; } void AddShape( std::shared_ptr aShape ) { // Don't make clients deal with nested SHAPE_COMPOUNDs if( dynamic_cast( aShape.get() ) ) { std::vector subshapes; aShape->GetIndexableSubshapes( subshapes ); for( const SHAPE* subshape : subshapes ) m_shapes.push_back( subshape->Clone() ); } else { m_shapes.push_back( aShape->Clone() ); } m_dirty = true; } bool Empty() const { return m_shapes.empty(); } int Size() const { return (int) m_shapes.size(); } void Rotate( const EDA_ANGLE& aAngle, const VECTOR2I& aCenter = { 0, 0 } ) override; bool IsSolid() const override; SHAPE* UniqueSubshape() const { return m_shapes.size() != 1 ? nullptr : m_shapes[0]; } virtual bool HasIndexableSubshapes() const override { return true; } virtual size_t GetIndexableSubshapeCount() const override { return m_shapes.size(); } virtual void GetIndexableSubshapes( std::vector& aSubshapes ) const override { aSubshapes.clear(); aSubshapes.reserve( m_shapes.size() ); std::copy( m_shapes.begin(), m_shapes.end(), std::back_inserter( aSubshapes ) ); } void TransformToPolygon( SHAPE_POLY_SET& aBuffer, int aError, ERROR_LOC aErrorLoc ) const override; private: BOX2I m_cachedBBox; bool m_dirty; std::vector m_shapes; }; #endif // __SHAPE_COMPOUND_H