Nim lang

Have some feature requests, feedback, cool stuff to share, or want to know where FreeCAD is going? This is the place.
Forum rules
Be nice to others! Read the FreeCAD code of conduct!
Post Reply
mantielero
Posts: 17
Joined: Sat Feb 09, 2019 10:15 am

Nim lang

Post by mantielero »

I was searching the forum for other programming languages: rust, julia, lua, lisp, ... came to my mind. There aren't many threads about this topic. The reason is obvious: there is a huge base already done in C++ and Python. Adding other languages increase the fragmentation, bindings are probably another issue and a lot more issues that I cannot spot (I am not a pro-developper).

And about Nim... what the f*ck is Nim? Who uses it? What is its position among the most used languages? One hundred something? I read Nim entering Tiobe 100 in March 2020 for the first time (not sure if that is true to be honest). So it is not popular.

So first, why it is a bad idea Nim and Freecad together? Freecad relies on libraries for which there are no bindings in Nim. Not only OCCT, but also Qt and Coin3D.

But I like the idea of Nim and Freecad playing together. Nim is compiled and garbage collected. So it feels like Go, but it faster and more powerful (more complex also). When you write it, it feels like python, but more functional. Somehow, it solves the two language problem as Julia (well in Freecad it would imply the 3 language problem!). Besides, it has meta-programming so you can create DSL like this. Creating DSL's for specific tasks (like the workbenches could be awesome). Nim compiles to C, C++ and JavaScript. Could this be useful for webbased Freecad? I think so. This is done in nimx or fidget.

I have been playing creating some OCCT bindings (not even at 1%, because I struggle with C++). Not a big win for very simple code like bottle example or here . But even with such small examples, there some wins:

Code: Select all

import occt # Only this is needed (not a hundred lines of includes
I added some sugar when dealing with points, directions, vectors, ... so:

Code: Select all

var p1 = Pnt(1.0, 0.2, 2.3)
echo p1  # Pretty prints: Pnt(x:1.0, y:0.2, z:2.3)
echo p1.x # Prints: 1.0
p1[0] = 1.2  # Assign 1.2 to x
p1.x = 1.3   # Assigns 1.3
So no big wins when things are so simple.

So just playing. I just wanted to share it with you.
mantielero
Posts: 17
Joined: Sat Feb 09, 2019 10:15 am

Re: Nim lang

Post by mantielero »

Some progress: the bottle example:

Code: Select all

import occt
import std/[math]

proc main() =
  # Profile : Define Support Points
  let  # immutable
    myWidth = 50.0
    myThickness = 20.0
    myHeight = 70.0
    aPnt1 = pnt(-myWidth / 2.0, 0, 0)
    aPnt2 = pnt(-myWidth / 2.0, -myThickness / 4.0, 0)
    aPnt3 = pnt(0, -myThickness / 2.0, 0)
    aPnt4 = pnt(myWidth / 2.0, -myThickness / 4.0, 0)
    aPnt5 = pnt(myWidth / 2.0, 0, 0)
  #echo typeof( aPnt1 )  # Use this to print the type of the variable

  # Profile : Define the Geometry
  let # immutable
    aArcOfCircle = arcCircle(aPnt2,aPnt3,aPnt4) # MakeArcOfCircle
    aSegment1    = segment(aPnt1, aPnt2)  # MakeSegment --(converter)--> Handle[GeomTrimmedCurve] 
    aSegment2    = segment(aPnt4, aPnt5)
    # Note: HandleGeomCurve = Handle[GeomCurve] 
    # Note: HandleGeomTrimmedCurve should inherit from HandleGeomCurve

  # Profile: Define the Topology
  # Converting suporting geometry
  var # mutable
    aEdge1 = edge(aSegment1)    
    aEdge2 = edge(aArcOfCircle)
    aEdge3 = edge(aSegment2)   

    aWire = wire(aEdge1, aEdge2, aEdge3)


    # Profile: Completing the Profile
    aOrigin = pnt(0, 0, 0)
    xDir    = dir(1, 0, 0)
    xAxis   = ax1(aOrigin, xDir)
    # gp_Ax1 xAxis = gp::OX();

  # Complete Profile
  var aTrsf:TrsfObj
  aTrsf.setMirror(xAxis)

  # apply the transformation 
  var aBRepTrsf:BRepBuilderAPI_Transform = transform(aWire, aTrsf)
  
  var aMirroredShape:TopoDS_Shape  = aBRepTrsf.shape


  # Get the wire from the shape
  let aMirroredWire:TopoDS_Wire = aMirroredShape.wire  # newTopoDS_WBRepAlgo_BooleanOperationire(aMirroredShape) #

  # Join the wires into a shape
  var mkWire = wire() #:BRepBuilderAPI_MakeWire
  mkWire.add(aWire)
  mkWire.add(aMirroredWire)
  let myWireProfile:TopoDS_Wire = mkWire.wire 

  # Body : Prim the Profile
  let myFaceProfile:TopoDS_Face = face(myWireProfile)
  let aPrismVec = vec(0, 0, myHeight)
  var myBody:TopoDS_Shape = prism(myFaceProfile, aPrismVec)  # BRepPrimAPI_MakePrism


  # - Applying fillets
  var mkFillet = fillet(myBody)

  for anEdge in myBody.getEdges():
    mkFillet.add(myThickness / 12.0, anEdge)

  myBody = mkFillet.shape()

  # Adding the Neck
  let neckLocation = pnt(0, 0, myHeight)
  let neckAxis     = dzAsDir()
  let neckAx2      = ax2(neckLocation, neckAxis)

  let myNeckRadius = myThickness / 4.0
  let myNeckHeight = myHeight / 10.0

  var mkCylinder = cylinder(neckAx2, myNeckRadius, myNeckHeight)
  var myNeck = mkCylinder.shape()
   

  myBody = fuse(myBody, myNeck)

  # Creating a Hollowed Solid
  var faceToRemove:TopoDS_Face 
  var zMax = -1f

  for aFace in myBody.getFaces():
    var aSurface = aface.surface 
    if aSurface.isGeomPlane:  # Consider only plane surfaces
      var aPlane = aSurface.toPlane
      var aPnt = aPlane.location()      
      var aZ = aPnt.z() 

      if aZ > zMax: # We get the plane surface with the highest Z value
        zMax = aZ
        faceToRemove = aFace

  var facesToRemove:TopTools_ListOfShape
  facesToRemove.append(faceToRemove)
  var aSolidMaker:ThickSolid
  aSolidMaker.makeThickSolidByJoin(myBody, facesToRemove, -myThickness / 50.0, 1.0e-3)
  myBody = aSolidMaker.shape()

  # ======================== Threading
  # Threading : Create Surfaces
  var aCyl1 = cylindricalSurface(neckAx2.ax3, myNeckRadius * 0.99)
  var aCyl2 = cylindricalSurface(neckAx2.ax3, myNeckRadius * 1.05)  

  # Threading : Define 2D Curves
  var aPnt   = pnt2d(2f * PI, myNeckHeight / 2f)
  var aDir   = dir2d(2f * PI, myNeckHeight / 4f)
  var anAx2d = ax2d(aPnt, aDir)

  var aMajor = 2f * PI
  var aMinor = myNeckHeight / 10f

  var anEllipse1 = ellipse(anAx2d, aMajor, aMinor) 
  var anEllipse2 = ellipse(anAx2d, aMajor, aMinor/4f)  

  var anArc1 = trimmedCurve(anEllipse1, 0f, PI)
  var anArc2 = trimmedCurve(anEllipse2, 0f, PI)

  var anEllipsePnt1 = anEllipse1.getPnt(0f)
  var anEllipsePnt2 = anEllipse2.getPnt(PI)

  var aSegment = segment(anEllipsePnt1, anEllipsePnt2).toHandleGeom2dTrimmedCurve 


  # Threading : Build Edges and Wires 
  var anEdge1OnSurf1 = edge(anArc1, aCyl1)
  var anEdge2OnSurf1 = edge(aSegment, aCyl1)
  var anEdge1OnSurf2 = edge(anArc2, aCyl2)
  var anEdge2OnSurf2 = edge(aSegment, aCyl2)

  var threadingWire1 = wire(anEdge1OnSurf1, anEdge2OnSurf1)
  var threadingWire2 = wire(anEdge1OnSurf2, anEdge2OnSurf2)

  # Threading : Build Edges and Wires
  # FIXME
  buildCurves3d(threadingWire1)
  buildCurves3d(threadingWire2)

  # Create Threading
  var aTool = newBRepOffsetAPI_ThruSections(true)
  aTool.addWire(threadingWire1)
  aTool.addWire(threadingWire2)
  aTool.checkCompatibility(false)
  var myThreading = aTool.shape()

  # Building the Resulting Compound 
  var aRes:TopoDS_Compound
  var aBuilder:BRepBuilder
  aBuilder.makeCompound(aRes)
  aBuilder.add(aRes, myBody)
  aBuilder.add(aRes, myThreading)  
  aRes.toStep("bottle.stp")

main()
This following code compiles and run it:

Code: Select all

nim cpp -r bottle.nim
The C++ generated code under the hood looks like:

Code: Select all

/* Generated by Nim Compiler v1.6.10 */
/* Compiled for: Linux, amd64, gcc */
/* Command for C compiler:
   g++ -c -std=gnu++14 -funsigned-char  -w -fmax-errors=3 -fpermissive -I/usr/include/opencascade/ -I/usr/import/opencascade/ -O3 -fno-strict-aliasing -fno-ident   -I/home/jose/.choosenim/toolchains/nim-1.6.10/lib -I/home/jose/src/nimlang/occt.nim/examples -o /home/jose/src/nimlang/occt.nim/examples/borrame/@mbottle.nim.cpp.o /home/jose/src/nimlang/occt.nim/examples/borrame/@mbottle.nim.cpp */
#define NIM_INTBITS 64

#include "nimbase.h"
#include "gp_Pnt.hxx"
#include "GC_MakeArcOfCircle.hxx"
#include "GC_Root.hxx"
#include "GC_MakeSegment.hxx"
#include "BRepBuilderAPI_MakeEdge.hxx"
#include "BRepBuilderAPI_MakeShape.hxx"
#include "BRepBuilderAPI_Command.hxx"
#include "BRepBuilderAPI_MakeWire.hxx"
#include "gp_Dir.hxx"
#include "gp_Ax1.hxx"
#include "gp_Trsf.hxx"
#include "BRepBuilderAPI_Transform.hxx"
#include "BRepBuilderAPI_ModifyShape.hxx"
#include "TopoDS_Shape.hxx"
#include "TopoDS_Wire.hxx"
#include "TopoDS.hxx"
#include "TopoDS_Face.hxx"
#include "BRepBuilderAPI_MakeFace.hxx"
#include "gp_Vec.hxx"
#include "BRepPrimAPI_MakePrism.hxx"
#include "BRepFilletAPI_MakeFillet.hxx"
#include "BRepFilletAPI_LocalOperation.hxx"
#include "ChFi3d_FilletShape.hxx"
#include "TopoDS_Edge.hxx"
#include "TopExp_Explorer.hxx"
#include "TopAbs_ShapeEnum.hxx"
#include "gp.hxx"
#include "gp_Ax2.hxx"
#include "BRepPrimAPI_MakeCylinder.hxx"
#include "BRepPrimAPI_MakeOneAxis.hxx"
#include "BRepAlgoAPI_Fuse.hxx"
#include "Standard_Handle.hxx"
#include "Geom_Surface.hxx"
#include "Geom_Geometry.hxx"
#include "Standard_Transient.hxx"
#include "BRep_Tool.hxx"
#include "Geom_Plane.hxx"
#include "Geom_ElementarySurface.hxx"
#include "NCollection_List.hxx"
#include "NCollection_BaseList.hxx"
#include "BRepOffsetAPI_MakeThickSolid.hxx"
#include "GeomAbs_JoinType.hxx"
#include "Message_ProgressRange.hxx"
#include "Geom_CylindricalSurface.hxx"
#include "gp_Ax3.hxx"
#include "gp_Pnt2d.hxx"
#include "gp_Dir2d.hxx"
#include "gp_Ax2d.hxx"
#include "Geom2d_Ellipse.hxx"
#include "Geom2d_Conic.hxx"
#include "Geom2d_Curve.hxx"
#include "Geom2d_Geometry.hxx"
#include "Geom2d_TrimmedCurve.hxx"
#include "Geom2d_BoundedCurve.hxx"
#include "GCE2d_MakeSegment.hxx"
#include "BRepLib.hxx"
#include "BRepOffsetAPI_ThruSections.hxx"
#include "TopoDS_Compound.hxx"
#include "BRep_Builder.hxx"
#include "TopoDS_Builder.hxx"
#undef LANGUAGE_C
#undef MIPSEB
#undef MIPSEL
#undef PPC
#undef R3000
#undef R4000
#undef i386
#undef linux
#undef mips
#undef near
#undef far
#undef powerpc
#undef unix
#define nimfr_(x, y)
#define nimln_(x, y)
struct RootObj;
struct TNimType;
struct TNimNode;
struct NimStringDesc;
struct TGenericSeq;
typedef NU8 tyEnum_TNimKind__jIBKr1ejBgsfM33Kxw4j7A;
typedef NU8 tySet_tyEnum_TNimTypeFlag__v8QUszD1sWlSIWZz7mC4bQ;
typedef N_NIMCALL_PTR(void, tyProc__ojoeKfW4VYIm36I9cpDTQIg) (void* p, NI op);
typedef N_NIMCALL_PTR(void*, tyProc__WSm2xU5ARYv9aAR4l0z9c9auQ) (void* p);
struct TNimType {
NI size;
NI align;
tyEnum_TNimKind__jIBKr1ejBgsfM33Kxw4j7A kind;
tySet_tyEnum_TNimTypeFlag__v8QUszD1sWlSIWZz7mC4bQ flags;
TNimType* base;
TNimNode* node;
void* finalizer;
tyProc__ojoeKfW4VYIm36I9cpDTQIg marker;
tyProc__WSm2xU5ARYv9aAR4l0z9c9auQ deepcopy;
};
struct RootObj {
TNimType* m_type;
};
typedef opencascade::handle<Geom_Surface> TY__Nv8CuwQI9bu9bXCzGbZytEGw;
typedef opencascade::handle<Geom_Plane> TY__N31bfHM17sbp19byE9cYw8hw;
typedef NCollection_List<TopoDS_Shape> TY__GIqsjlKJHsTq0jbUI9bnu9aw;
typedef NU8 tyEnum_BRepOffset_Mode__Xm2Lugv8wC5Qu8DdfizkYw;
typedef opencascade::handle<Geom_CylindricalSurface> TY__lHd1o8jXLURddx63Idqd9aQ;
typedef opencascade::handle<Geom2d_Ellipse> TY__RkXz1PGFjIpHLx0HtSizJg;
typedef opencascade::handle<Geom2d_TrimmedCurve> TY__gr9cHpXf2T9bJg9bMQ9cd8A9cDQ;
struct TGenericSeq {
NI len;
NI reserved;
};
struct NimStringDesc : public TGenericSeq {
NIM_CHAR data[SEQ_DECL_SIZE];
};
N_LIB_PRIVATE N_NIMCALL(void, main__bottle_3)(void);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt, pnt__bottle_7)(NF x, NI y, NI z);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt, pnt__bottle_16)(NF x, NF y, NI z);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt, pnt__bottle_25)(NI x, NF y, NI z);
N_LIB_PRIVATE N_NIMCALL(BRepBuilderAPI_MakeEdge, edge__OOZsrcZlibZgcZgc_8)(GC_MakeSegment obj);
N_LIB_PRIVATE N_NIMCALL(BRepBuilderAPI_MakeEdge, edge__OOZsrcZlibZgcZgc_38)(GC_MakeArcOfCircle obj);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt, pnt__bottle_57)(NI x, NI y, NI z);
N_LIB_PRIVATE N_NIMCALL(gp_Dir, dir__bottle_66)(NI x, NI y, NI z);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt, pnt__bottle_96)(NI x, NI y, NF z);
N_LIB_PRIVATE N_NIMCALL(TY__N31bfHM17sbp19byE9cYw8hw, toPlane__OOZsrcZlibZgeomZgeom_33)(TY__Nv8CuwQI9bu9bXCzGbZytEGw aSurface);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt, location__OOZsrcZlibZgeomZgeom_42)(TY__N31bfHM17sbp19byE9cYw8hw aPlane);
N_LIB_PRIVATE N_NIMCALL(TY__lHd1o8jXLURddx63Idqd9aQ, cylindricalSurface__OOZsrcZlibZgeomZgeom_7)(gp_Ax3 a3, float radius);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt2d, getPnt__bottle_162)(TY__RkXz1PGFjIpHLx0HtSizJg c, NF32 val);
N_LIB_PRIVATE N_NIMCALL(gp_Pnt2d, getPnt__bottle_208)(TY__RkXz1PGFjIpHLx0HtSizJg c, NF val);
N_LIB_PRIVATE N_NIMCALL(void, toSTEP__bottle_251)(TopoDS_Compound solid, NimStringDesc* fname);
static N_INLINE(void, initStackBottomWith)(void* locals);
N_LIB_PRIVATE N_NOINLINE(void, nimGC_setStackBottom)(void* theStackBottom);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot10atslibatssystemdotnim_DatInit000)(void);
N_LIB_PRIVATE N_NIMCALL(void, atmdotdotatsdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot10atslibatssystemdotnim_Init000)(void);
N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void);
STRING_LITERAL(TM__4g2DTPBeLnQTIbR5Tv9aR9ag_2, "bottle.stp", 10);
N_LIB_PRIVATE N_NIMCALL(void, main__bottle_3)(void) {
	gp_Trsf aTrsf;
	TopoDS_Face faceToRemove;
	TY__GIqsjlKJHsTq0jbUI9bnu9aw facesToRemove;
	BRepOffsetAPI_MakeThickSolid aSolidMaker;
	Message_ProgressRange T31_;
	NIM_BOOL T36_;
	NIM_BOOL T37_;
	TopoDS_Compound aRes;
	BRep_Builder aBuilder;
	NF myWidth = 50.0;
	NF myThickness = 20.0;
	NF myHeight = 70.0;
	gp_Pnt T1_ = pnt__bottle_7(((NF)(-(myWidth)) / (NF)(2.0)), ((NI) 0), ((NI) 0));
	gp_Pnt aPnt1 = T1_;
	gp_Pnt T2_ = pnt__bottle_16(((NF)(-(myWidth)) / (NF)(2.0)), ((NF)(-(myThickness)) / (NF)(4.0)), ((NI) 0));
	gp_Pnt aPnt2 = T2_;
	gp_Pnt T3_ = pnt__bottle_25(((NI) 0), ((NF)(-(myThickness)) / (NF)(2.0)), ((NI) 0));
	gp_Pnt aPnt3 = T3_;
	gp_Pnt T4_ = pnt__bottle_16(((NF)(myWidth) / (NF)(2.0)), ((NF)(-(myThickness)) / (NF)(4.0)), ((NI) 0));
	gp_Pnt aPnt4 = T4_;
	gp_Pnt T5_ = pnt__bottle_7(((NF)(myWidth) / (NF)(2.0)), ((NI) 0), ((NI) 0));
	gp_Pnt aPnt5 = T5_;
	GC_MakeArcOfCircle aArcOfCircle(aPnt2, aPnt3, aPnt4);
	GC_MakeSegment aSegment1(aPnt1, aPnt2);
	GC_MakeSegment aSegment2(aPnt4, aPnt5);
	BRepBuilderAPI_MakeEdge T6_ = edge__OOZsrcZlibZgcZgc_8(aSegment1);
	BRepBuilderAPI_MakeEdge aEdge1 = T6_;
	BRepBuilderAPI_MakeEdge T7_ = edge__OOZsrcZlibZgcZgc_38(aArcOfCircle);
	BRepBuilderAPI_MakeEdge aEdge2 = T7_;
	BRepBuilderAPI_MakeEdge T8_ = edge__OOZsrcZlibZgcZgc_8(aSegment2);
	BRepBuilderAPI_MakeEdge aEdge3 = T8_;
	BRepBuilderAPI_MakeWire aWire((aEdge1), (aEdge2), (aEdge3));
	gp_Pnt T9_ = pnt__bottle_57(((NI) 0), ((NI) 0), ((NI) 0));
	gp_Pnt aOrigin = T9_;
	gp_Dir T10_ = dir__bottle_66(((NI) 1), ((NI) 0), ((NI) 0));
	gp_Dir xDir = T10_;
	gp_Ax1 xAxis(aOrigin, xDir);
	aTrsf.SetMirror(xAxis);
	BRepBuilderAPI_Transform aBRepTrsf(aWire.BRepBuilderAPI_MakeShape::operator TopoDS_Shape(), aTrsf, NIM_FALSE);
	TopoDS_Shape aMirroredShape = aBRepTrsf.Shape();
	TopoDS_Wire aMirroredWire = TopoDS::Wire(aMirroredShape);
	BRepBuilderAPI_MakeWire mkWire;
	mkWire.Add(aWire.BRepBuilderAPI_MakeWire::operator TopoDS_Wire());
	mkWire.Add(aMirroredWire);
	TopoDS_Wire myWireProfile = mkWire.Wire();
	TopoDS_Face myFaceProfile = BRepBuilderAPI_MakeFace(myWireProfile, NIM_FALSE).BRepBuilderAPI_MakeFace::operator TopoDS_Face();
	gp_Vec aPrismVec(0.0f, 0.0f, ((float) (myHeight)));
	TopoDS_Shape myBody = BRepPrimAPI_MakePrism(myFaceProfile, aPrismVec, NIM_FALSE, NIM_TRUE).BRepBuilderAPI_MakeShape::operator TopoDS_Shape();
	BRepFilletAPI_MakeFillet mkFillet(myBody, ((ChFi3d_FilletShape) 0));
	{
		TopoDS_Edge anEdge;
		TopExp_Explorer anEdgeExplorer(myBody, ((TopAbs_ShapeEnum) 6), ((TopAbs_ShapeEnum) 8));
		{
			while (1) {
				NIM_BOOL T14_ = anEdgeExplorer.More();
				if (!T14_) goto LA13;
				anEdge = TopoDS::Edge(anEdgeExplorer.Current());
				mkFillet.Add(((float) (((NF)(myThickness) / (NF)(12.0)))), anEdge);
				anEdgeExplorer.Next();
			} LA13: ;
		}
	}
	myBody = mkFillet.Shape();
	gp_Pnt T15_ = pnt__bottle_96(((NI) 0), ((NI) 0), myHeight);
	gp_Pnt neckLocation = T15_;
	gp_Dir neckAxis = gp::DZ();
	gp_Ax2 neckAx2(neckLocation, neckAxis);
	NF myNeckRadius = ((NF)(myThickness) / (NF)(4.0));
	NF myNeckHeight = ((NF)(myHeight) / (NF)(10.0));
	BRepPrimAPI_MakeCylinder mkCylinder(neckAx2, ((float) (myNeckRadius)), ((float) (myNeckHeight)));
	TopoDS_Shape myNeck = mkCylinder.Shape();
	myBody = BRepAlgoAPI_Fuse(myBody, myNeck).BRepBuilderAPI_MakeShape::operator TopoDS_Shape();
	NF32 zMax = -1.0f;
	{
		TopoDS_Face aFace;
		TopExp_Explorer aFaceExplorer(myBody, ((TopAbs_ShapeEnum) 4), ((TopAbs_ShapeEnum) 8));
		{
			while (1) {
				NIM_BOOL T19_ = aFaceExplorer.More();
				if (!T19_) goto LA18;
				aFace = TopoDS::Face(aFaceExplorer.Current());
				TY__Nv8CuwQI9bu9bXCzGbZytEGw aSurface = BRep_Tool::Surface(aFace);
				{
					if (!(aSurface->DynamicType() == Geom_Plane::get_type_descriptor())) goto LA22_;
{					TY__N31bfHM17sbp19byE9cYw8hw T24_ = toPlane__OOZsrcZlibZgeomZgeom_33(aSurface);
					TY__N31bfHM17sbp19byE9cYw8hw aPlane = T24_;
					gp_Pnt T25_ = location__OOZsrcZlibZgeomZgeom_42(aPlane);
					gp_Pnt aPnt = T25_;
					float aZ = aPnt.Z();
					{
						if (!(zMax < aZ)) goto LA28_;
{						zMax = aZ;
						faceToRemove = aFace;
}					}
					LA28_: ;
}				}
				LA22_: ;
				aFaceExplorer.Next();
			} LA18: ;
		}
	}
	TopoDS_Shape T30_ = facesToRemove.Append(faceToRemove);
	aSolidMaker.MakeThickSolidByJoin(myBody, facesToRemove, ((NF)(-(myThickness)) / (NF)(50.0)), 0.001, ((tyEnum_BRepOffset_Mode__Xm2Lugv8wC5Qu8DdfizkYw) 0), NIM_FALSE, NIM_FALSE, ((GeomAbs_JoinType) 0), NIM_FALSE, T31_);
	myBody = aSolidMaker.Shape();
	TY__lHd1o8jXLURddx63Idqd9aQ T32_ = cylindricalSurface__OOZsrcZlibZgeomZgeom_7(gp_Ax3(neckAx2), ((float) (((NF)(myNeckRadius) * (NF)(0.99)))));
	TY__lHd1o8jXLURddx63Idqd9aQ aCyl1 = T32_;
	TY__lHd1o8jXLURddx63Idqd9aQ T33_ = cylindricalSurface__OOZsrcZlibZgeomZgeom_7(gp_Ax3(neckAx2), ((float) (((NF)(myNeckRadius) * (NF)(1.05)))));
	TY__lHd1o8jXLURddx63Idqd9aQ aCyl2 = T33_;
	gp_Pnt2d aPnt_2(6.2831855f, ((float) (((NF)(myNeckHeight) / (NF)(2.0f)))));
	gp_Dir2d aDir(6.2831855f, ((float) (((NF)(myNeckHeight) / (NF)(4.0f)))));
	gp_Ax2d anAx2d(aPnt_2, aDir);
	NF aMajor = 6.283185307179586;
	NF aMinor = ((NF)(myNeckHeight) / (NF)(10.0f));
	TY__RkXz1PGFjIpHLx0HtSizJg anEllipse1 = new Geom2d_Ellipse(anAx2d, ((float) (aMajor)), ((float) (aMinor)));
	TY__RkXz1PGFjIpHLx0HtSizJg anEllipse2 = new Geom2d_Ellipse(anAx2d, ((float) (aMajor)), ((float) (((NF)(aMinor) / (NF)(4.0f)))));
	TY__gr9cHpXf2T9bJg9bMQ9cd8A9cDQ anArc1 = new Geom2d_TrimmedCurve(anEllipse1, 0.0f, 3.1415927f, NIM_TRUE, NIM_TRUE);
	TY__gr9cHpXf2T9bJg9bMQ9cd8A9cDQ anArc2 = new Geom2d_TrimmedCurve(anEllipse2, 0.0f, 3.1415927f, NIM_TRUE, NIM_TRUE);
	gp_Pnt2d T34_ = getPnt__bottle_162(anEllipse1, 0.0f);
	gp_Pnt2d anEllipsePnt1 = T34_;
	gp_Pnt2d T35_ = getPnt__bottle_208(anEllipse2, 3.141592653589793);
	gp_Pnt2d anEllipsePnt2 = T35_;
	opencascade::handle<Geom2d_TrimmedCurve> aSegment = (Handle_Geom2d_TrimmedCurve)(GCE2d_MakeSegment(anEllipsePnt1, anEllipsePnt2));
	TopoDS_Edge anEdge1OnSurf1 = BRepBuilderAPI_MakeEdge(anArc1, aCyl1);
	TopoDS_Edge anEdge2OnSurf1 = BRepBuilderAPI_MakeEdge(aSegment, aCyl1);
	TopoDS_Edge anEdge1OnSurf2 = BRepBuilderAPI_MakeEdge(anArc2, aCyl2);
	TopoDS_Edge anEdge2OnSurf2 = BRepBuilderAPI_MakeEdge(aSegment, aCyl2);
	BRepBuilderAPI_MakeWire threadingWire1(anEdge1OnSurf1, anEdge2OnSurf1);
	BRepBuilderAPI_MakeWire threadingWire2(anEdge1OnSurf2, anEdge2OnSurf2);
	T36_ = (NIM_BOOL)0;
	T36_ = BRepLib::BuildCurves3d(threadingWire1);
	T37_ = (NIM_BOOL)0;
	T37_ = BRepLib::BuildCurves3d(threadingWire2);
	BRepOffsetAPI_ThruSections aTool(NIM_TRUE, NIM_FALSE, 0.000001);
	aTool.AddWire(threadingWire1.BRepBuilderAPI_MakeWire::operator TopoDS_Wire());
	aTool.AddWire(threadingWire2.BRepBuilderAPI_MakeWire::operator TopoDS_Wire());
	aTool.CheckCompatibility(NIM_FALSE);
	TopoDS_Shape myThreading = aTool.Shape();
	aBuilder.MakeCompound(aRes);
	aBuilder.Add(aRes, myBody);
	aBuilder.Add(aRes, myThreading);
	toSTEP__bottle_251(aRes, ((NimStringDesc*) &TM__4g2DTPBeLnQTIbR5Tv9aR9ag_2));
}
static N_INLINE(void, initStackBottomWith)(void* locals) {
	nimGC_setStackBottom(locals);
}

N_LIB_PRIVATE void PreMainInner(void) {
}

N_LIB_PRIVATE int cmdCount;
N_LIB_PRIVATE char** cmdLine;
N_LIB_PRIVATE char** gEnv;
N_LIB_PRIVATE void PreMain(void) {
	void (*volatile inner)(void);
	inner = PreMainInner;
	atmdotdotatsdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot10atslibatssystemdotnim_DatInit000();
	initStackBottomWith((void *)&inner);
	atmdotdotatsdotdotatsdotdotatsdotdotatsdotchoosenimatstoolchainsatsnimminus1dot6dot10atslibatssystemdotnim_Init000();
	(*inner)();
}

N_LIB_PRIVATE N_CDECL(void, NimMainInner)(void) {
	NimMainModule();
}

N_CDECL(void, NimMain)(void) {
	void (*volatile inner)(void);
	PreMain();
	inner = NimMainInner;
	initStackBottomWith((void *)&inner);
	(*inner)();
}

int main(int argc, char** args, char** env) {
	cmdLine = args;
	cmdCount = argc;
	gEnv = env;
	NimMain();
	return nim_program_result;
}

N_LIB_PRIVATE N_NIMCALL(void, NimMainModule)(void) {
{
	main__bottle_3();
}
}
grd
Posts: 328
Joined: Wed Apr 13, 2022 5:13 am
Location: Eindhoven, The Netherlands

Re: Nim lang

Post by grd »

Yes, I like Nim a lot too. I talked about Nim [1, 2] in the GSoC Call for ideas. To me, the comparison with Python isn't really correct. Yes, Nim has the "look and feel" of Python, but I compare it more with C++ without it's history and quirks, because Nim is much more advanced than Python and also completely type-safe and Nim also does have Qt bindings [3] and that library looks to me rather complete, which is a major undertaking. OCCT lacks things of course so it can't be used for any serious work ATM and I don't think that anyone has ever took the effort to create Nim bindings for Coin3D and of course also not for FreeCAD itself, which makes it hard but I think that the purpose of Nim should be to extend FreeCAD, because then you don't need to write C++ anymore. Especially in the gaming industry Nim is being used a lot and that is done only to extend, not to replace the code, because for those guys the performance is important and that counts too for the CAD industry that (I think) is completely written in C++.

To make Nim happen, the only thing that needs to be done is writing header bindings (and I think also the cmake things because nimqt uses qmake). After that you are gonna write in a Python-like language.

To me, there are no downsides when you use Nim, only benefits.


[1] viewtopic.php?p=659000#p659000
[2] viewtopic.php?p=659732#p659732
[3] https://github.com/jerous86/nimqt
About Nim. Latest Release 2.0.2. Here is Nim in 100 seconds and a Nim package. There are Qt and OCCT packages.
mantielero
Posts: 17
Joined: Sat Feb 09, 2019 10:15 am

Re: Nim lang

Post by mantielero »

Looking into RepliCAD, I played with the idea of creating a similar looking API. There is where Nim starts to shine.
The Replicad code looks like:

Code: Select all

  let shape = draw([-myWidth / 2, 0])
    .vLine(-myThickness / 4)
    .threePointsArc(myWidth, 0, myWidth / 2, -myThickness / 4)
    .vLine(myThickness / 4)
    .closeWithMirror()
    .sketchOnPlane()
    .extrude(myHeight)
    .fillet(myThickness / 12);

  const myNeckRadius = myThickness / 4;
  const myNeckHeight = myHeight / 10;
  const neck = makeCylinder(
    myNeckRadius,
    myNeckHeight,
    [0, 0, myHeight],
    [0, 0, 1]
  );

  shape = shape.fuse(neck);

  shape = shape.shell(myThickness / 50, (f) =>
    f.inPlane("XY", [0, 0, myHeight + myNeckHeight])
  );
The Nim code is not too far:

Code: Select all

  let
    myWidth     = 50.0
    myThickness = 20.0
    myHeight    = 70.0

  var myBody = start(-myWidth / 2, 0)    # starting point
              .vline(-myThickness / 4)   # vertical line for a distance
                                          # arc using the last point, this point and next point
              .threePointsArc( 0, -myThickness / 2.0, #myWidth, 0, 
                              myWidth / 2, -myThickness / 4)
              .vLine( myThickness / 4)
              .closeWithMirror
              .extrude( myHeight )
              .fillet(myThickness / 12)

  let
    myNeckRadius = myThickness / 4
    myNeckHeight = myHeight / 10

  var myNeck = cylinder( myNeckRadius, 
                         myNeckHeight,
                         pnt(0, 0, myHeight),
                         dir(0,0,1) )
  
  myBody = myBody.fuse( myNeck )

  # make a shell from a hollowed solid
  myBody = mybody.shell( -myThickness / 50,  # bottle thickness
                         mybody.getPlaneZmax ) # hollowed by removing the top face
The Nim code is compiled. It creates 14 c++ files.

For example, the function getPlaneZmax is translated into:

Code: Select all

N_LIB_PRIVATE N_NIMCALL(TopoDS_Face, getPlaneZmax__OOZOOZsrcZlibZexplorerZexplorer_41)(TopoDS_Shape body) {
	TopoDS_Face result;
	NF T1_ = low__OOZOOZsrcZlibZexplorerZexplorer_44();
	NF zMax = T1_;
	{
		TopoDS_Face aFace;
		{
			TopoDS_Face face;
			TopExp_Explorer aFaceExplorer(body, ((TopAbs_ShapeEnum) 4), ((TopAbs_ShapeEnum) 8));
			{
				while (1) {
					NIM_BOOL T6_ = aFaceExplorer.More();
					if (!T6_) goto LA5;
					face = TopoDS::Face(aFaceExplorer.Current());
					TY__Nv8CuwQI9bu9bXCzGbZytEGw surface = BRep_Tool::Surface(face);
					{
						if (!(surface->DynamicType() == Geom_Plane::get_type_descriptor())) goto LA9_;
{						aFace = face;
						TY__N31bfHM17sbp19byE9cYw8hw T11_ = toPlane__OOZOOZsrcZlibZgeomZgeom_33(BRep_Tool::Surface(aFace));
						gp_Pnt T12_ = location__OOZOOZsrcZlibZgeomZgeom_42(T11_);
						gp_Pnt aPnt = T12_;
						float aZ = aPnt.Z();
						{
							if (!(zMax < ((NF) (aZ)))) goto LA15_;
{							zMax = ((NF) (aZ));
							result = aFace;
}						}
						LA15_: ;
}					}
					LA9_: ;
					aFaceExplorer.Next();
				} LA5: ;
			}
		}
	}
	return result;
}
grd
Posts: 328
Joined: Wed Apr 13, 2022 5:13 am
Location: Eindhoven, The Netherlands

Re: Nim lang

Post by grd »

Can you tell me what the status is of https://github.com/mantielero/occt.nim ? You wrapped quite a lot of code! But what works and what not? I saw that you did dealt with `rounds`. I have to say that I am impressed by your work. Of course it isn't finished but I am impressed!
About Nim. Latest Release 2.0.2. Here is Nim in 100 seconds and a Nim package. There are Qt and OCCT packages.
mantielero
Posts: 17
Joined: Sat Feb 09, 2019 10:15 am

Re: Nim lang

Post by mantielero »

That is a very difficult question to answer. Well actually the answer is easy: I don't know. :?

Right now, it is just my playground. The library is mostly untested. On the other hand, the ammount of opencascade covered is big. OpenCascade contains around 7700 header files. There are around 2600 nim files for that part. So whenever I try to do something is not too difficult to make it work. Sometimes I miss a package, but now it is not too difficult to support a new package thanks to c2nim.

Right now I am trying to implement some of the ideas from RepliCAD or cadquery.

So the summary is: it is far from being production ready, but at least now I feel that some effort produce significant progress.
grd
Posts: 328
Joined: Wed Apr 13, 2022 5:13 am
Location: Eindhoven, The Netherlands

Re: Nim lang

Post by grd »

mantielero wrote: Sat Mar 04, 2023 7:29 pm Right now, it is just my playground. The library is mostly untested. On the other hand, the ammount of opencascade covered is big. OpenCascade contains around 7700 header files. There are around 2600 nim files for that part. So whenever I try to do something is not too difficult to make it work. Sometimes I miss a package, but now it is not too difficult to support a new package thanks to c2nim.
Do you also know the CADRays library from OCCT? This is really interesting because it allows to use materials and rendering. You can look here: viewtopic.php?t=21339

But I have a question. You use Linux. How do you know the number of header files? And also is it possible to use c2nim with a for loop to use c2nim for all the headers in a directory and after that start to refactor is? I am asking this because of FreeCAD itself. How many header files does FreeCAD have?
Right now I am trying to implement some of the ideas from RepliCAD or cadquery.

So the summary is: it is far from being production ready, but at least now I feel that some effort produce significant progress.
But there is progress 8-) I like it.
About Nim. Latest Release 2.0.2. Here is Nim in 100 seconds and a Nim package. There are Qt and OCCT packages.
mantielero
Posts: 17
Joined: Sat Feb 09, 2019 10:15 am

Re: Nim lang

Post by mantielero »

CADRays is paid tool AFAIK. I am more into blender. Freecad supports luxrender and povray.

Counting the number of headers is easy:

Code: Select all

$ ls /usr/include/opencascade/*.hxx | wc -l
7741
Yes, you can put c2nim in loop, but you normally need to preprocess the headers (in particular with complex libraries like occt). It required lots of manual work. I created a file for each package like this one: https://github.com/mantielero/occt.nim/ ... d/gen.nims

This wraps many functions that probably are not needed.
grd
Posts: 328
Joined: Wed Apr 13, 2022 5:13 am
Location: Eindhoven, The Netherlands

Re: Nim lang

Post by grd »

mantielero wrote: Tue Mar 07, 2023 8:41 pm CADRays is paid tool AFAIK. I am more into blender. Freecad supports luxrender and povray.
Well, yes and no. You can pay of course but it is open source: viewtopic.php?p=322755&sid=d4e55c0ad079 ... d2#p322755

And it doesn't have Linux support :evil:
Counting the number of headers is easy:

Code: Select all

$ ls /usr/include/opencascade/*.hxx | wc -l
7741
In the freecad-source directory I did it with this command

Code: Select all

find . -iname "*.h" -type f | wc -l
The total ATM is 1673. That is quite a lot!
Yes, you can put c2nim in loop, but you normally need to preprocess the headers (in particular with complex libraries like occt). It required lots of manual work. I created a file for each package like this one: https://github.com/mantielero/occt.nim/ ... d/gen.nims

This wraps many functions that probably are not needed.
My question was a bit stupid, I know.
About Nim. Latest Release 2.0.2. Here is Nim in 100 seconds and a Nim package. There are Qt and OCCT packages.
grd
Posts: 328
Joined: Wed Apr 13, 2022 5:13 am
Location: Eindhoven, The Netherlands

Re: Nim lang

Post by grd »

Did you saw this? https://www.youtube.com/watch?v=Cdr4-cOsAWA

Nim is all about extending C++, because Nim is better!
About Nim. Latest Release 2.0.2. Here is Nim in 100 seconds and a Nim package. There are Qt and OCCT packages.
Post Reply