228 lines
7.2 KiB
C++
228 lines
7.2 KiB
C++
#include "SketchFeature.h"
|
|
#include "SketchObject.h"
|
|
#include "SketchLine.h"
|
|
#include "SketchRectangle.h"
|
|
#include "SketchCircle.h"
|
|
|
|
#include <BRepBuilderAPI_MakeEdge.hxx>
|
|
#include <BRepBuilderAPI_MakeWire.hxx>
|
|
#include <BRepBuilderAPI_MakeFace.hxx>
|
|
#include <BRep_Builder.hxx>
|
|
#include <TopoDS_Compound.hxx>
|
|
#include <TopoDS.hxx>
|
|
#include <gp_Circ.hxx>
|
|
#include <gp_Ax2.hxx>
|
|
#include <TopExp_Explorer.hxx>
|
|
#include <ShapeAnalysis_FreeBounds.hxx>
|
|
#include <gp_Pln.hxx>
|
|
#include <BRepOffsetAPI_MakeFilling.hxx>
|
|
#include <GeomAbs_Shape.hxx>
|
|
|
|
#include <QJsonArray>
|
|
#include <QDebug>
|
|
|
|
SketchFeature::SketchFeature(const QString& name)
|
|
: Feature(name)
|
|
{
|
|
}
|
|
|
|
SketchFeature::~SketchFeature()
|
|
{
|
|
qDeleteAll(m_objects);
|
|
}
|
|
|
|
QString SketchFeature::type() const
|
|
{
|
|
return "Sketch";
|
|
}
|
|
|
|
void SketchFeature::setPlane(SketchPlane plane)
|
|
{
|
|
m_plane = plane;
|
|
}
|
|
|
|
SketchFeature::SketchPlane SketchFeature::plane() const
|
|
{
|
|
return m_plane;
|
|
}
|
|
|
|
const TopoDS_Shape& SketchFeature::shape() const
|
|
{
|
|
return m_shape;
|
|
}
|
|
|
|
void SketchFeature::buildShape()
|
|
{
|
|
m_shape.Nullify();
|
|
QList<TopoDS_Edge> lineEdges;
|
|
QList<TopoDS_Face> faces;
|
|
|
|
gp_Pln sketchPlane;
|
|
switch (m_plane) {
|
|
case SketchPlane::XY: sketchPlane = gp_Pln(gp::Origin(), gp::DY()); break;
|
|
case SketchPlane::XZ: sketchPlane = gp_Pln(gp::Origin(), gp::DZ()); break;
|
|
case SketchPlane::YZ: sketchPlane = gp_Pln(gp::Origin(), gp::DX()); break;
|
|
}
|
|
|
|
for (SketchObject* obj : m_objects) {
|
|
if (auto line = dynamic_cast<SketchLine*>(obj)) {
|
|
BRepBuilderAPI_MakeEdge makeEdge(line->startPoint(), line->endPoint());
|
|
if (makeEdge.IsDone()) {
|
|
lineEdges.append(makeEdge.Edge());
|
|
}
|
|
} else if (auto rect = dynamic_cast<SketchRectangle*>(obj)) {
|
|
const gp_Pnt& c1 = rect->corner1();
|
|
const gp_Pnt& c2 = rect->corner2();
|
|
gp_Pnt other_corner1, other_corner2;
|
|
|
|
if (m_plane == SketchPlane::XY) {
|
|
other_corner1.SetCoord(c2.X(), c1.Y(), c1.Z());
|
|
other_corner2.SetCoord(c1.X(), c1.Y(), c2.Z());
|
|
} else if (m_plane == SketchPlane::XZ) {
|
|
other_corner1.SetCoord(c2.X(), c1.Y(), c1.Z());
|
|
other_corner2.SetCoord(c1.X(), c2.Y(), c1.Z());
|
|
} else { // YZ
|
|
other_corner1.SetCoord(c1.X(), c2.Y(), c1.Z());
|
|
other_corner2.SetCoord(c1.X(), c1.Y(), c2.Z());
|
|
}
|
|
|
|
BRepBuilderAPI_MakeEdge me1(c1, other_corner1);
|
|
BRepBuilderAPI_MakeEdge me2(other_corner1, c2);
|
|
BRepBuilderAPI_MakeEdge me3(c2, other_corner2);
|
|
BRepBuilderAPI_MakeEdge me4(other_corner2, c1);
|
|
if (me1.IsDone() && me2.IsDone() && me3.IsDone() && me4.IsDone()) {
|
|
BRepBuilderAPI_MakeWire wireBuilder(me1.Edge(), me2.Edge(), me3.Edge(), me4.Edge());
|
|
if (wireBuilder.IsDone()) {
|
|
BRepBuilderAPI_MakeFace faceBuilder(sketchPlane, wireBuilder.Wire());
|
|
if (faceBuilder.IsDone()) {
|
|
faces.append(faceBuilder.Face());
|
|
}
|
|
}
|
|
}
|
|
} else if (auto circle = dynamic_cast<SketchCircle*>(obj)) {
|
|
const gp_Pnt& center = circle->center();
|
|
double radius = circle->radius();
|
|
gp_Dir normal;
|
|
switch (m_plane) {
|
|
case SketchPlane::XY: normal = gp::DY(); break;
|
|
case SketchPlane::XZ: normal = gp::DZ(); break;
|
|
case SketchPlane::YZ: normal = gp::DX(); break;
|
|
}
|
|
gp_Ax2 axis(center, normal);
|
|
gp_Circ circ(axis, radius);
|
|
BRepBuilderAPI_MakeEdge makeEdge(circ);
|
|
if (makeEdge.IsDone()) {
|
|
TopoDS_Edge edge = makeEdge.Edge();
|
|
BRepBuilderAPI_MakeWire wireBuilder(edge);
|
|
if(wireBuilder.IsDone()) {
|
|
BRepBuilderAPI_MakeFace faceBuilder(sketchPlane, wireBuilder.Wire());
|
|
if (faceBuilder.IsDone()) {
|
|
faces.append(faceBuilder.Face());
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
if (!lineEdges.isEmpty()) {
|
|
qDebug() << "buildShape: processing" << lineEdges.size() << "line edges";
|
|
|
|
BRepOffsetAPI_MakeFilling faceMaker;
|
|
for (const TopoDS_Edge& edge : lineEdges) {
|
|
faceMaker.Add(edge, GeomAbs_C0);
|
|
}
|
|
faceMaker.Build();
|
|
|
|
if (faceMaker.IsDone()) {
|
|
TopExp_Explorer explorer(faceMaker.Shape(), TopAbs_FACE);
|
|
int facesAdded = 0;
|
|
for (; explorer.More(); explorer.Next()) {
|
|
faces.append(TopoDS::Face(explorer.Current()));
|
|
facesAdded++;
|
|
}
|
|
qDebug() << "buildShape: added" << facesAdded << "face(s) using MakeFilling";
|
|
} else {
|
|
qDebug() << "buildShape: MakeFilling failed";
|
|
}
|
|
}
|
|
|
|
qDebug() << "buildShape: total faces created:" << faces.size();
|
|
if (faces.isEmpty()) {
|
|
return;
|
|
}
|
|
|
|
if (faces.size() == 1) {
|
|
m_shape = faces.first();
|
|
} else {
|
|
TopoDS_Compound compound;
|
|
BRep_Builder builder;
|
|
builder.MakeCompound(compound);
|
|
for (const auto& face : faces) {
|
|
builder.Add(compound, face);
|
|
}
|
|
m_shape = compound;
|
|
}
|
|
}
|
|
|
|
void SketchFeature::addObject(SketchObject* object)
|
|
{
|
|
m_objects.append(object);
|
|
}
|
|
|
|
const QList<SketchObject*>& SketchFeature::objects() const
|
|
{
|
|
return m_objects;
|
|
}
|
|
|
|
void SketchFeature::read(const QJsonObject& json)
|
|
{
|
|
Feature::read(json);
|
|
if (json.contains("plane") && json["plane"].isString()) {
|
|
QString planeStr = json["plane"].toString();
|
|
if (planeStr == "XY") m_plane = SketchPlane::XY;
|
|
else if (planeStr == "XZ") m_plane = SketchPlane::XZ;
|
|
else if (planeStr == "YZ") m_plane = SketchPlane::YZ;
|
|
}
|
|
|
|
if (json.contains("objects") && json["objects"].isArray()) {
|
|
QJsonArray objectsArray = json["objects"].toArray();
|
|
qDeleteAll(m_objects);
|
|
m_objects.clear();
|
|
for (const QJsonValue& value : objectsArray) {
|
|
QJsonObject objectJson = value.toObject();
|
|
if (objectJson.contains("type") && objectJson["type"].isString()) {
|
|
QString type = objectJson["type"].toString();
|
|
if (type == "Line") {
|
|
auto line = new SketchLine();
|
|
line->read(objectJson);
|
|
m_objects.append(line);
|
|
} else if (type == "Rectangle") {
|
|
auto rect = new SketchRectangle();
|
|
rect->read(objectJson);
|
|
m_objects.append(rect);
|
|
}
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
void SketchFeature::write(QJsonObject& json) const
|
|
{
|
|
Feature::write(json);
|
|
QString planeStr;
|
|
switch (m_plane) {
|
|
case SketchPlane::XY: planeStr = "XY"; break;
|
|
case SketchPlane::XZ: planeStr = "XZ"; break;
|
|
case SketchPlane::YZ: planeStr = "YZ"; break;
|
|
}
|
|
json["plane"] = planeStr;
|
|
|
|
QJsonArray objectsArray;
|
|
for (const auto& object : m_objects) {
|
|
QJsonObject objectJson;
|
|
object->write(objectJson);
|
|
objectsArray.append(objectJson);
|
|
}
|
|
json["objects"] = objectsArray;
|
|
}
|