Example #1
0
static void SimplifySketch(const double deviation, bool make_bspline )
{

    wxGetApp().CreateUndoPoint();

    double original_tolerance = wxGetApp().m_geom_tol;
    wxGetApp().m_geom_tol = sketch_tool_options.m_cleanup_tolerance;

    std::list<HeeksObj *> selected_sketches;
    std::copy( wxGetApp().m_marked_list->list().begin(), wxGetApp().m_marked_list->list().end(),
                std::inserter( selected_sketches, selected_sketches.begin() ));

	std::list<HeeksObj*>::const_iterator It;
	for(It = selected_sketches.begin(); It != selected_sketches.end(); It++){
		HeeksObj* object = *It;
		std::list<HeeksObj *> new_objects;

		if (object->GetType() == SketchType)
		{
			std::list<TopoDS_Shape> wires;
			try {
				heekscad_interface.ConvertSketchToFaceOrWire(object, wires, false);
			} // End try
			catch(...)
			{
				continue;
			}
			for (std::list<TopoDS_Shape>::iterator itWire = wires.begin(); itWire != wires.end(); itWire++)
			{
				std::list<SimplifySketchTool::SortPoint> points = SimplifySketchTool::GetPoints( TopoDS::Wire(*itWire), deviation );

				if (sketch_tool_options.m_sort_points)
				{
					// The sort points option is turned on.  The idea of this is to detect shapes that include
					// sections that 'double back' on themselves.  The first example being a shape made up of
					// a box as well as a single line that layed along one edge of the box.  In this case the extra
					// line was superfluous.  If we sort the points so that each point is closest to the previous
					// point then, hopefully, we will reorder these shapes that double back on themselves.  If this
					// doesn't work then the user can always turn the 'sort points' option off and try again.

					std::vector<SimplifySketchTool::SortPoint> sorted_points;
					std::copy( points.begin(), points.end(), std::inserter( sorted_points, sorted_points.begin() ));

					for (std::vector<SimplifySketchTool::SortPoint>::iterator l_itPoint = sorted_points.begin(); l_itPoint != sorted_points.end(); l_itPoint++)
					{
						// We've already begun.  Just sort based on the previous point's location.
						std::vector<SimplifySketchTool::SortPoint>::iterator l_itNextPoint = l_itPoint;
						l_itNextPoint++;

						if (l_itNextPoint != sorted_points.end())
						{
							SimplifySketchTool::sort_points_by_distance compare( *l_itPoint );
							std::sort( l_itNextPoint, sorted_points.end(), compare );
						} // End if - then
					} // End for

					points.clear();
					std::copy( sorted_points.begin(), sorted_points.end(), std::inserter( points, points.begin() ));

					// This sorting process will have resulted in the start and end points being located next to each other
					// and hence removed.  If the original wire was periodic (closed shape) then make sure the last point
					// is the same as the first point.

					TopoDS_Wire wire(TopoDS::Wire(*itWire));
					if (wire.Closed())
					{
						if (*(points.begin()) != *(points.rbegin()))
						{
							points.push_back(*points.begin());	// Close the shape manually.
						}
					}
				}

				// Whether we sorted or not, we may want to close the shape.
				if (sketch_tool_options.m_force_closed_shape)
				{
					if (*(points.begin()) != *(points.rbegin()))
					{
						points.push_back(*points.begin());	// Close the shape manually.
					}
				}

				// Now keep removing points from this list as long as the midpoints are within deviation of
				// the line between the two neighbour points.
				bool points_removed = false;
				do {
					points_removed = false;

					for (std::list<SimplifySketchTool::SortPoint>::iterator itPoint = points.begin(); itPoint != points.end(); itPoint++ )
					{
						std::list<SimplifySketchTool::SortPoint>::iterator itP1 = itPoint;
						std::list<SimplifySketchTool::SortPoint>::iterator itP2 = itPoint;
						std::list<SimplifySketchTool::SortPoint>::iterator itP3 = itPoint;

						itP2++;
						if (itP2 != points.end())
						{
							itP3 = itP2;
							itP3++;

							if (itP3 != points.end())
							{
								// First see if p1 and p2 are too close to each other.
								if (itP1->Distance(*itP2) < deviation)
								{
									// Discard p2.
									points.erase(itP2);
									points_removed = true;
									continue;
								}

								if (itP2->Distance(*itP3) < deviation)
								{
									// Discard p2
									points.erase(itP2);
									points_removed = true;
									continue;
								}

                                if (itP1->Distance(*itP3) > deviation)
                                {
                                    // Now draw a line between p1 and p3.  Measure the distance between p2 and the nearest point
                                    // along that line.  If this distance is less than the max deviation then discard p2.
                                    gp_Lin line(*itP1, gp_Dir(itP3->X() - itP1->X(), itP3->Y() - itP1->Y(), itP3->Z() - itP1->Z()));
                                    if (line.SquareDistance(*itP2) < deviation)
                                    {
                                        // Discard p2
                                        points.erase(itP2);
                                        points_removed = true;
                                        continue;
                                    }
                                }
							}
						}
					} // End for
				} while (points_removed == true);

				if (points.size() >= 2)
				{
					


				    if (make_bspline)
				    {
				        try {
                            TColgp_Array1OfPnt Points(0, points.size()-1);
                            Standard_Integer i=0;
                            for (std::list<SimplifySketchTool::SortPoint>::iterator itPoint = points.begin(); itPoint != points.end(); itPoint++, i++)
                            {
                                Points.SetValue(i, *itPoint);
                            }

                            // GeomAPI_PointsToBSpline bspline(Points);

                            GeomAPI_PointsToBSpline bspline(Points,
                                                            sketch_tool_options.m_degree_min,
                                                            sketch_tool_options.m_degree_max,
                                                            GeomAbs_Shape(sketch_tool_options.m_continuity),
                                                            sketch_tool_options.m_cleanup_tolerance);

                            // Standard_EXPORT GeomAPI_PointsToBSpline(const TColgp_Array1OfPnt& Points,const Standard_Integer DegMin = 3,const Standard_Integer DegMax = 8,const GeomAbs_Shape Continuity = GeomAbs_C2,const Standard_Real Tol3D = 1.0e-3);

                            HSpline *hspline = new HSpline(bspline.Curve(), &(wxGetApp().current_color));
                            heekscad_interface.Add( hspline, NULL );
				        }
				        catch (Standard_Failure) {
                            Handle_Standard_Failure e = Standard_Failure::Caught();
                            wxMessageBox(_("Failed to create BSpline curve"));
                        }
				    } // End if - then
				    else
				    {
				        // We're making straight lines

                        HeeksObj *sketch = heekscad_interface.NewSketch();
                        for (std::list<SimplifySketchTool::SortPoint>::iterator itPoint = points.begin(); itPoint != points.end(); itPoint++)
                        {
                            std::list<SimplifySketchTool::SortPoint>::iterator itNext = itPoint;
                            itNext++;
                            if (itNext == points.end()) continue;

                            double start[3], end[3];
                            itPoint->ToDoubleArray(start);
                            itNext->ToDoubleArray(end);

                            sketch->Add(heekscad_interface.NewLine(start, end), NULL);
                        } // End for

                        // heekscad_interface.Add(sketch, NULL);
                        new_objects.push_back(sketch);
				    } // End if - else
				} // End if - then
			} // End for

            if (new_objects.size() > 0)
            {
#ifdef MULTIPLE_OWNERS
                std::list<HeeksObj *> parents = object->Owners();
                for (std::list<HeeksObj *>::iterator itOwner = parents.begin(); itOwner != parents.end(); itOwner++)
                {
#else
				if(object->m_owner)
				{
#endif
                    if ((object->CanEditString()) && (object->GetShortString()))
                    {
                        // (*itOwner)->Remove(object);

                        // Mark the old sketches with a name that can be easily recognised so that we can delete the
                        // old objects if we're satisfied with the replacements.
                        wxString title;
                        title << _("Replaced ") << object->GetShortString();
                        object->OnEditString(title);
                    } // End if - then

                    for (std::list<HeeksObj *>::iterator itNewChild = new_objects.begin(); itNewChild != new_objects.end(); itNewChild++)
                    {
#ifdef MULTIPLE_OWNERS
                        (*itOwner)->Add( *itNewChild, NULL );
#else
                        object->m_owner->Add( *itNewChild, NULL );
#endif
                    } // End for
                } // End for
            } // End if - then
		} // End if - then
	} // End for

    wxGetApp().m_geom_tol = original_tolerance;
    wxGetApp().Changed();
}

void SimplifySketchTool::Run()
{
    SimplifySketch(m_deviation, false);
} // End Run() method
Example #2
0
/**
	We can see what diameter tool was used to create the pocket or contour child operation.  We assume
	that this has already occured.  We want to fit down into the slot cut by these operations as far
	as possible but only touching the appropriate side of the material (inside or outside).
	We also need to make sure we don't go too deep.  If the chamfering bit is small while the endmill
	used to cut the profile or contour was large then we may need to limit the depth of cut.
 */
Python CChamfer::AppendTextForProfileChildren(
	CMachineState *pMachineState,
	const double theta,
	HeeksObj *child,
	CTool *pChamferingBit )
{
	Python python;

	unsigned int number_of_bad_sketches = 0;
	double tolerance = heeksCAD->GetTolerance();

	double start_depth = 0.0;
	double final_depth = 0.0;
	double clearance_height = 0.0;
	double rapid_safety_space = 0.0;
	std::list<HeeksObj *> sketches;

	CDepthOp *pDepthOp = dynamic_cast<CDepthOp *>(child);
	if (pDepthOp == NULL)
	{
		start_depth = m_depth_op_params.m_start_depth;
		final_depth = m_depth_op_params.m_final_depth;
		clearance_height = m_depth_op_params.ClearanceHeight();
		rapid_safety_space = m_depth_op_params.m_rapid_safety_space;

		if (child->GetType() == SketchType)
		{
			sketches.push_back(child);
		}
	}
	else
	{
		start_depth = pDepthOp->m_depth_op_params.m_start_depth;
		final_depth = pDepthOp->m_depth_op_params.m_final_depth;
		clearance_height = pDepthOp->m_depth_op_params.ClearanceHeight();
		rapid_safety_space = pDepthOp->m_depth_op_params.m_rapid_safety_space;

		for (HeeksObj *object = child->GetFirstChild(); object != NULL; object = child->GetNextChild())
		{
			if (object->GetType() == SketchType)
			{
				sketches.push_back(object);
			}
		}
	}

	for (std::list<HeeksObj *>::iterator itChild = sketches.begin(); itChild != sketches.end(); itChild++)
    {
		HeeksObj *object = *itChild;

        std::list<TopoDS_Shape> wires;
        if (! heeksCAD->ConvertSketchToFaceOrWire( object, wires, false))
        {
            number_of_bad_sketches++;
        } // End if - then
        else
        {
            // The wire(s) represent the sketch objects for a tool path.
            if (object->GetShortString() != NULL)
            {
				wxString comment;
				comment << _T("Chamfering of ") << object->GetShortString();
                python << _T("comment(") << PythonString(comment).c_str() << _T(")\n");
            }

            try {
                for(std::list<TopoDS_Shape>::iterator It2 = wires.begin(); It2 != wires.end(); It2++)
                {
                    TopoDS_Shape& wire_to_fix = *It2;
                    ShapeFix_Wire fix;
                    fix.Load( TopoDS::Wire(wire_to_fix) );
                    fix.FixReorder();

                    TopoDS_Shape wire = fix.Wire();

                    wire = pMachineState->Fixture().Adjustment(wire);

                    BRepOffsetAPI_MakeOffset offset_wire(TopoDS::Wire(wire));

                    // Now generate a toolpath along this wire.
                    std::list<double> depths = GetProfileChamferingDepths(child);

                    for (std::list<double>::iterator itDepth = depths.begin(); itDepth != depths.end(); itDepth++)
                    {
                        double radius = pChamferingBit->CuttingRadius(false,fabs(*itDepth - start_depth));

						// We know what offset we'd really like.  See how far we can offset the shape before we start
                        // getting cross-over of graphics.
                        double max_offset = CInlay::FindMaxOffset( radius, TopoDS::Wire(wire), radius / 10.0 );

						if (radius > max_offset) radius = max_offset;

						// Now move the tool slightly less than this offset so that the chamfering width is
						// produced.
						double theta = pChamferingBit->m_params.m_cutting_edge_angle / 360.0 * 2.0 * PI;
						radius -= this->m_params.m_chamfer_width * sin(theta);

						switch (child->GetType())
						{
						case ProfileType:
							if (((CProfile *) child)->m_profile_params.m_tool_on_side == CProfileParams::eLeftOrOutside) radius *= +1.0;
							if (((CProfile *) child)->m_profile_params.m_tool_on_side == CProfileParams::eRightOrInside) radius *= -1.0;
							if (((CProfile *) child)->m_profile_params.m_tool_on_side == CProfileParams::eOn) radius *= +1.0;
							break;

						case ContourType:
							if (((CContour *) child)->m_params.m_tool_on_side == CContourParams::eLeftOrOutside) radius *= +1.0;
							if (((CContour *) child)->m_params.m_tool_on_side == CContourParams::eRightOrInside) radius *= -1.0;
							if (((CContour *) child)->m_params.m_tool_on_side == CContourParams::eOn) radius *= +1.0;
							break;

						case PocketType:
							radius *= -1.0;
							break;

						default:
							if (m_params.m_tool_on_side == CContourParams::eLeftOrOutside) radius *= +1.0;
							if (m_params.m_tool_on_side == CContourParams::eRightOrInside) radius *= -1.0;
							if (m_params.m_tool_on_side == CContourParams::eOn) radius *= +1.0;
							break;
						} // End switch

                        TopoDS_Wire tool_path_wire(TopoDS::Wire(wire));

                        double offset = radius;
                        if (offset < 0) offset *= -1.0;

                        if (offset > tolerance)
                        {
                            offset_wire.Perform(radius);
                            if (! offset_wire.IsDone())
                            {
                                break;
                            }
                            tool_path_wire = TopoDS::Wire(offset_wire.Shape());
                        }

                        if (offset > tolerance)
                        {
                            gp_Trsf matrix;

                            matrix.SetTranslation( gp_Vec( gp_Pnt(0,0,0), gp_Pnt( 0,0,*itDepth)));
                            BRepBuilderAPI_Transform transform(matrix);
                            transform.Perform(tool_path_wire, false); // notice false as second parameter
                            tool_path_wire = TopoDS::Wire(transform.Shape());

							python << CContour::GCode(	tool_path_wire,
                                                        pMachineState,
                                                        clearance_height,
                                                        rapid_safety_space,
                                                        start_depth,
                                                        CContourParams::ePlunge );
                        } // End if - then
                    } // End for
                } // End for
            } // End try
            catch (Standard_Failure & error) {
                (void) error;	// Avoid the compiler warning.
                Handle_Standard_Failure e = Standard_Failure::Caught();
                number_of_bad_sketches++;
            } // End catch
        } // End if - else
    } // End for

    if (pMachineState->Location().Z() < (m_depth_op_params.ClearanceHeight() / theApp.m_program->m_units))
    {
        // Move up above workpiece to relocate to the start of the next operation.
        python << _T("rapid(z=") << m_depth_op_params.ClearanceHeight() / theApp.m_program->m_units << _T(")\n");

        CNCPoint where(pMachineState->Location());
        where.SetZ(m_depth_op_params.ClearanceHeight() / theApp.m_program->m_units);
        pMachineState->Location(where);
    }

    if (number_of_bad_sketches > 0)
    {
        wxString message;
        message << _("Failed to create contours around ") << number_of_bad_sketches << _(" sketches");
        wxMessageBox(message);
    }

	return(python);
}