Files
create/src/Mod/Part/App/FaceMaker.cpp
DeepSOIC 115c7e4f88 Part: FaceMaker: check if instance is actually created.
Part::FaceMaker::ConstructFromType() could return null pointer if
abstract class type is supplied.

Here, it is fixed by checking for null pointer in facemaker itself,
rather than in every place  ConstructFromType is being used.
2016-10-04 10:03:19 +02:00

186 lines
6.5 KiB
C++

/***************************************************************************
* Copyright (c) 2016 Victor Titov (DeepSOIC) <vv.titov@gmail.com> *
* *
* This file is part of the FreeCAD CAx development system. *
* *
* This library is free software; you can redistribute it and/or *
* modify it under the terms of the GNU Library General Public *
* License as published by the Free Software Foundation; either *
* version 2 of the License, or (at your option) any later version. *
* *
* This library 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 Library General Public License for more details. *
* *
* You should have received a copy of the GNU Library General Public *
* License along with this library; see the file COPYING.LIB. If not, *
* write to the Free Software Foundation, Inc., 59 Temple Place, *
* Suite 330, Boston, MA 02111-1307, USA *
* *
***************************************************************************/
#include "PreCompiled.h"
#ifndef _PreComp_
# include <TopoDS.hxx>
# include <TopoDS_Iterator.hxx>
# include <BRep_Builder.hxx>
# include <BRepBuilderAPI_MakeWire.hxx>
# include <BRepBuilderAPI_MakeFace.hxx>
# include <BRep_Tool.hxx>
#endif
#include "FaceMaker.h"
#include <Base/Exception.h>
#include <memory>
#include <QtGlobal>
TYPESYSTEM_SOURCE_ABSTRACT(Part::FaceMaker, Base::BaseClass);
TYPESYSTEM_SOURCE_ABSTRACT(Part::FaceMakerPublic, Part::FaceMaker);
void Part::FaceMaker::addWire(const TopoDS_Wire& w)
{
this->addShape(w);
}
void Part::FaceMaker::addShape(const TopoDS_Shape& sh)
{
if(sh.IsNull())
throw Base::ValueError("Input shape is null.");
switch(sh.ShapeType()){
case TopAbs_COMPOUND:
this->myCompounds.push_back(TopoDS::Compound(sh));
break;
case TopAbs_WIRE:
this->myWires.push_back(TopoDS::Wire(sh));
break;
case TopAbs_EDGE:
this->myWires.push_back(BRepBuilderAPI_MakeWire(TopoDS::Edge(sh)).Wire());
break;
default:
throw Base::TypeError("Shape must be a wire, edge or compound. Something else was supplied.");
break;
}
this->mySourceShapes.push_back(sh);
}
void Part::FaceMaker::useCompound(const TopoDS_Compound& comp)
{
TopoDS_Iterator it(comp);
for(; it.More(); it.Next()){
this->addShape(it.Value());
}
}
const TopoDS_Face& Part::FaceMaker::Face()
{
const TopoDS_Shape &sh = this->Shape();
if(sh.IsNull())
throw Base::Exception("Part::FaceMaker: result shape is null.");
if (sh.ShapeType() != TopAbs_FACE)
throw Base::TypeError("Part::FaceMaker: return shape is not a single face.");
return TopoDS::Face(sh);
}
void Part::FaceMaker::Build()
{
this->NotDone();
this->myShapesToReturn.clear();
this->myGenerated.Clear();
this->Build_Essence();//adds stuff to myShapesToReturn
for(const TopoDS_Compound& cmp : this->myCompounds){
std::unique_ptr<FaceMaker> facemaker = Part::FaceMaker::ConstructFromType(this->getTypeId());
facemaker->useCompound(cmp);
facemaker->Build();
const TopoDS_Shape &subfaces = facemaker->Shape();
if (subfaces.IsNull())
continue;
if (subfaces.ShapeType() == TopAbs_COMPOUND){
this->myShapesToReturn.push_back(subfaces);
} else {
//result is not a compound (probably, a face)... but we want to follow compounding structure of input, so wrap it into compound.
TopoDS_Builder builder;
TopoDS_Compound cmp_res;
builder.MakeCompound(cmp_res);
builder.Add(cmp_res,subfaces);
this->myShapesToReturn.push_back(cmp_res);
}
}
if(this->myShapesToReturn.empty()){
//nothing to do, null shape will be returned.
} else if (this->myShapesToReturn.size() == 1){
this->myShape = this->myShapesToReturn[0];
} else {
TopoDS_Builder builder;
TopoDS_Compound cmp_res;
builder.MakeCompound(cmp_res);
for(TopoDS_Shape &sh: this->myShapesToReturn){
builder.Add(cmp_res,sh);
}
this->myShape = cmp_res;
}
this->Done();
}
std::unique_ptr<Part::FaceMaker> Part::FaceMaker::ConstructFromType(const char* className)
{
Base::Type fmType = Base::Type::fromName(className);
if (fmType.isBad()){
std::stringstream ss;
ss << "Class '"<< className <<"' not found.";
throw Base::TypeError(ss.str().c_str());
}
return Part::FaceMaker::ConstructFromType(fmType);
}
std::unique_ptr<Part::FaceMaker> Part::FaceMaker::ConstructFromType(Base::Type type)
{
if (!type.isDerivedFrom(Part::FaceMaker::getClassTypeId())){
std::stringstream ss;
ss << "Class '" << type.getName() << "' is not derived from Part::FaceMaker.";
throw Base::TypeError(ss.str().c_str());
}
std::unique_ptr<FaceMaker> instance(static_cast<Part::FaceMaker*>(type.createInstance()));
if (!instance){
std::stringstream ss;
ss << "Cannot create FaceMaker from abstract type '" << type.getName() << "'";
throw Base::TypeError(ss.str().c_str());
}
return instance;
}
void Part::FaceMaker::throwNotImplemented()
{
throw Base::NotImplementedError("Not implemente yet...");
}
//----------------------------------------------------------------------------------------
TYPESYSTEM_SOURCE(Part::FaceMakerSimple, Part::FaceMakerPublic);
std::string Part::FaceMakerSimple::getUserFriendlyName() const
{
return std::string(QT_TRANSLATE_NOOP("Part_FaceMaker","Simple"));
}
std::string Part::FaceMakerSimple::getBriefExplanation() const
{
return std::string(QT_TRANSLATE_NOOP("Part_FaceMaker","Makes separate plane face from every wire independently. No support for holes; wires can be on different planes."));
}
void Part::FaceMakerSimple::Build_Essence()
{
for(TopoDS_Wire &w: myWires){
this->myShapesToReturn.push_back(BRepBuilderAPI_MakeFace(w).Shape());
}
}