NaroCAD gets shinier as it fixes in those two days small annoyances:
- scripting tab editing area gets wrong layout
- the changing name of a shape will not update the object list
- the default color should match the object's color, not a non initialized one (displayed as white)
- sourceforge bug reporter web page has changed the page form so the crashes were getting an 403 error (access forbidden)
- a crash may happen when Ellipse have zero size minor radius at design time
- NaroStarter will firstly try to find an existing OpenCascade installation. If it does not, it will use it's own bundled OpenCascade distribution. This is user friendly way. Also, in SVN exists an environment installer that brings to you the "native" dlls of OpenCascade for running NaroCAD.
NaroCAD has support to write unit tests (based on NUnit), but in fact many unit tests were never written because NaroCAD needs to create an OpenCascade view before adding even a simple line. Thus being said, makes unit testing in that area to be a non trivial task, also when it was an simpler issue like parametric modeling event propagation.
Right now there was reviewed the shape creation code to not depend on OpenCascade view and you can create your own test that works faster and well. Also, the tests are based on Document class, means that if you have a complex scene that you know that it crash NaroCAD, supposedly after creating a 3 extrude shapes, when you add an ellipse on top of them it will fail, you can design it in NaroCAD. Save it. You can load that three extrudes and make in your unit test to add the ellipse only.
So hopefully if we encounter crashes, we can create an unit test and add to NaroCAD test suite to not happen again.
At the end of the week I will post on SourceForge NaroCAD 1.0.1 that will include all those fixes, so you will be able to get away those small annoyances. It wil replace the 1.0 version. I pick the end of week to have time to not add regressions as I do those fixes.
Tuesday, June 30, 2009
Monday, June 29, 2009
Going one step further for next iteration
NaroCAD reaches 1.0 few days ago. So we found good things on this but we want to make things even better.
We want to:
- integrate NUnit to work for most part of project to make easier testable to reduce the crash cases. There will be parts that are harder to integrate, but the most parts should be there
- transformations to be accessible to user (translate, scale, rotate)
- squash found bugs
- installer work to target a Documents and Settings/Users folder to avoid problems on restricted permissions environment
- improve the solver to detect closed shapes,
On low priority are:
- GUI updates (automatic shape numbering and others)
- a way to organize better your work adding new helper controls, commands etc. (a help command line command)
We want to:
- integrate NUnit to work for most part of project to make easier testable to reduce the crash cases. There will be parts that are harder to integrate, but the most parts should be there
- transformations to be accessible to user (translate, scale, rotate)
- squash found bugs
- installer work to target a Documents and Settings/Users folder to avoid problems on restricted permissions environment
- improve the solver to detect closed shapes,
On low priority are:
- GUI updates (automatic shape numbering and others)
- a way to organize better your work adding new helper controls, commands etc. (a help command line command)
Saturday, June 27, 2009
NaroCAD 1.0 Released
NaroCAD reaches the first important milestone and we are proud to announce as NaroCAD 1.0
NaroCAD is an opensource CAD design tool written in C#/.NET and is built on top of proven OpenCascade library (www.opencascade.org). Also it provides wrappers for OpenCascade library that are accessible from any .NET language. This milestone is a hard work consisting in 1200 commits that adds a lot of features and we will point in short here:
- document model similar with OpenCascade's OCAF but C# based, using generics, easily debuggable. High performance undo/redo computing, serializable.
- the label's attributes are defined in a C#/.NET friendly way, no GUIDs involved, and the code of serializing/deserializing even complex types is trivial. You can work out of the box with the following types, but you can add on your own others: integer, double, string, color, reference
- clean shape definition using dependency solving notifications and easily make possible parametric programming. Separate dependency framewework that can be reused
- command line extensible framework so you can automate your new added shapes
- there is a solver component that let you get closest geometry. It is useful as it gives for user hints as long as he edit them.
- visual pipes&filters framework that you have access to various resources like: OpenCascade's context and view, document, open and save dialogs, solver. In case is too complex for you, there is a premade action that gets your custom function and creates everything for you.
- easy to work OpenCascade wrapping focused to minimize the lines you will write your own extensions
- decoupled code for most components, clean design
- and much more (integrated bug reporter, repository like update, IronPython integration, unit testing, etc.)
NaroCAD is opensource project, and you can take it's source at any given time from SourceForge's project homepage: https://sourceforge.net/projects/narocad/
If you are interested on site's blog activity you can read more here:
http://narocad.blogspot.com
You can download the release from SourceForge from here.
NaroCAD is an opensource CAD design tool written in C#/.NET and is built on top of proven OpenCascade library (www.opencascade.org). Also it provides wrappers for OpenCascade library that are accessible from any .NET language. This milestone is a hard work consisting in 1200 commits that adds a lot of features and we will point in short here:
- document model similar with OpenCascade's OCAF but C# based, using generics, easily debuggable. High performance undo/redo computing, serializable.
- the label's attributes are defined in a C#/.NET friendly way, no GUIDs involved, and the code of serializing/deserializing even complex types is trivial. You can work out of the box with the following types, but you can add on your own others: integer, double, string, color, reference
- clean shape definition using dependency solving notifications and easily make possible parametric programming. Separate dependency framewework that can be reused
- command line extensible framework so you can automate your new added shapes
- there is a solver component that let you get closest geometry. It is useful as it gives for user hints as long as he edit them.
- visual pipes&filters framework that you have access to various resources like: OpenCascade's context and view, document, open and save dialogs, solver. In case is too complex for you, there is a premade action that gets your custom function and creates everything for you.
- easy to work OpenCascade wrapping focused to minimize the lines you will write your own extensions
- decoupled code for most components, clean design
- and much more (integrated bug reporter, repository like update, IronPython integration, unit testing, etc.)
NaroCAD is opensource project, and you can take it's source at any given time from SourceForge's project homepage: https://sourceforge.net/projects/narocad/
If you are interested on site's blog activity you can read more here:
http://narocad.blogspot.com
You can download the release from SourceForge from here.
Preparing for 1.0 release
The last few days were quite difficult. We solved around 10-15 bugs every day, the application looks much better than on the previous week. And we are preparing now to make a release.
Posted two photos with the new splash that we made using NaroCad and with the part described in the the tutorial. The tutorial document is located on /trunk/narocad/ and can be launched also from the NaroCad help menu.
Friday, June 26, 2009
Installer working in one step with no other dependency...
Installer have been a tricky part for NaroCAD because NaroCAD is a .NET/C# based CAD application and when it crash that is missing dlls, etc. it will throw a C++ exception that is not possible to catch from C#. Also, some files are not obvious in OpenCascade usage as they were not dlls.
This was happen to be the first two problems. The last problem was that at least in the past it was considered as fact that NaroCAD have some dependencies supplied and if not NaroStarter will detect them. Because the installer should provide the Dlls without installing the corresponding applications, will make NaroStarter to not detect the environment problems as for certain there are no dlls implied.
Thus makes needed more changes and the hardest problem was that at any given time was needed to be tested under a virtual machine to make all things testable, making more than running a program and attaching the debugger.
But all things seems fixed right now. The installer right now grows to 16M as it comes with OpenCascade part inside. The single dependency (excluding Windows) is .NET 3.5. If you have updated Windows Vista or Windows 7, you will have them, if not (so you have Windows XP) you will need need to download it explicitly.
This was happen to be the first two problems. The last problem was that at least in the past it was considered as fact that NaroCAD have some dependencies supplied and if not NaroStarter will detect them. Because the installer should provide the Dlls without installing the corresponding applications, will make NaroStarter to not detect the environment problems as for certain there are no dlls implied.
Thus makes needed more changes and the hardest problem was that at any given time was needed to be tested under a virtual machine to make all things testable, making more than running a program and attaching the debugger.
But all things seems fixed right now. The installer right now grows to 16M as it comes with OpenCascade part inside. The single dependency (excluding Windows) is .NET 3.5. If you have updated Windows Vista or Windows 7, you will have them, if not (so you have Windows XP) you will need need to download it explicitly.
Wednesday, June 24, 2009
Bug fixing
Started fixing bugs, fixed most of the bugs related to draw line, draw rectangle, ellipse, extrude.
Still didn't fix the Solver and the Cut. Also Fillet needs some stabilization.
Still didn't fix the Solver and the Cut. Also Fillet needs some stabilization.
Tuesday, June 23, 2009
Again fixes and a benchmark (part II)
I had focused this day for some of last remaining NewShapeModifiers issues like zero length input. But most of the day I tried to what is the minimalist part installing. This means installing Windows in VM (thanks VirtualBox!) but still I am not find either which are the default VC Runtime 2008 SP1 dlls and how to enable them. Was a frustrating experience regarding installers and the fact that Windows does not have either bundles (as OS X does) or a package manager to say that NaroCAD need this, this and that, and if you don't have installed, the OS will do this job for you. But I still searching.
Do you remember this benchmark? This shows the scalability of NaroCAD engine. And the main limitation seem to be Undo on high level count shapes.
Entering a bit under the hood it was very easy to see why it was such an amount time (and was growing) doing Undo/Redo diff.
The algorithm of doing Undo was this: at every Document.Transact() call, there was a call to make a copy snapshot of the entire tree. This is time consuming, at least on high count of shapes. But this is only the first part of the story. At the Document.Commit call, there is another entire snapshot of the entire tree. At the end, those two trees are compared branch by branch and leaf by leaf to make two diffs: Undo diff and Redo diffs.
This approach is for sure safe, testable, the tree can be serialized to Xml (so this is the format that is saved in xml files, is the entire scene saved) but for sure is slow and it does a lot of computations that are not needed. Also, working on big trees, will create a lot of small objects on heap, and mostly strings that fragment deeply the heap.
The new algorithm right now was started from the day I've seen this bottleneck and was almost finished in weekend, only today I had did test if all tests are passing and do following optimizations:
- AutoTransact is Enable by default (means almost never you will serialize your entire tree)
- modified nodes are marked as changed, so the computation is not on entire tree, but on nodes that are changed. This will make a small overhead on access but it will pay off on undo in it's worst case.
Let's see the results:
As it seems, the increase in time for marking is under 10% for high count shapes so most users will not notice. The decrease in undo time means that you can work adding shape by shape.
Also, as I looked more in details, the Undo time include the UpdateUI code, which is constant (like updating the tree), and removing them from counting will mean for example that for adding 10K shapes, Undo only time (using the new algorithm is aproximatively 800ms, means that for 10k shapes the new algorithm is aproximatively 2 times faster, and the difference increase as much as the shape count increase. Adding at 10 k shapes three shapes, Undo takes with the new algorithm only 15 ms (excluding updating the UI).
What seems to be still the bottlenecks?
UI itself, means that if I will hide the TreeView, to not update it and to not generate the entire tree, excluding the first time is used.
OpenCascade is still the main issue, OpenCascade seems to be inoperable on high count of small shapes. Probably some efforts will improve it. OpenCascade seems to use glVertex/etc. in it's code and does not rely on VertexBuffer Objects (known as VBO) so it will be till the future refactor CPU bound, as glVertex & co OpenGL functions need a lot of driver work (as need to do transformations on CPU or at least to push them explicitly to graphic card frame by frame).
Doing testing I solved a crash on Document.Revert case, that was pretty hard to notice (if Revert was done in an inconsistent scene state, the Redo to it will make scene crash as was inconsistent, so was not either a Revert problem or a restore problem, but was because Restore keeps in redo list the last state that was inconsistent. The Revert right now do not save this in the list).
Do you remember this benchmark? This shows the scalability of NaroCAD engine. And the main limitation seem to be Undo on high level count shapes.
Entering a bit under the hood it was very easy to see why it was such an amount time (and was growing) doing Undo/Redo diff.
The algorithm of doing Undo was this: at every Document.Transact() call, there was a call to make a copy snapshot of the entire tree. This is time consuming, at least on high count of shapes. But this is only the first part of the story. At the Document.Commit call, there is another entire snapshot of the entire tree. At the end, those two trees are compared branch by branch and leaf by leaf to make two diffs: Undo diff and Redo diffs.
This approach is for sure safe, testable, the tree can be serialized to Xml (so this is the format that is saved in xml files, is the entire scene saved) but for sure is slow and it does a lot of computations that are not needed. Also, working on big trees, will create a lot of small objects on heap, and mostly strings that fragment deeply the heap.
The new algorithm right now was started from the day I've seen this bottleneck and was almost finished in weekend, only today I had did test if all tests are passing and do following optimizations:
- AutoTransact is Enable by default (means almost never you will serialize your entire tree)
- modified nodes are marked as changed, so the computation is not on entire tree, but on nodes that are changed. This will make a small overhead on access but it will pay off on undo in it's worst case.
Let's see the results:
As it seems, the increase in time for marking is under 10% for high count shapes so most users will not notice. The decrease in undo time means that you can work adding shape by shape.
Also, as I looked more in details, the Undo time include the UpdateUI code, which is constant (like updating the tree), and removing them from counting will mean for example that for adding 10K shapes, Undo only time (using the new algorithm is aproximatively 800ms, means that for 10k shapes the new algorithm is aproximatively 2 times faster, and the difference increase as much as the shape count increase. Adding at 10 k shapes three shapes, Undo takes with the new algorithm only 15 ms (excluding updating the UI).
What seems to be still the bottlenecks?
UI itself, means that if I will hide the TreeView, to not update it and to not generate the entire tree, excluding the first time is used.
OpenCascade is still the main issue, OpenCascade seems to be inoperable on high count of small shapes. Probably some efforts will improve it. OpenCascade seems to use glVertex/etc. in it's code and does not rely on VertexBuffer Objects (known as VBO) so it will be till the future refactor CPU bound, as glVertex & co OpenGL functions need a lot of driver work (as need to do transformations on CPU or at least to push them explicitly to graphic card frame by frame).
Doing testing I solved a crash on Document.Revert case, that was pretty hard to notice (if Revert was done in an inconsistent scene state, the Redo to it will make scene crash as was inconsistent, so was not either a Revert problem or a restore problem, but was because Restore keeps in redo list the last state that was inconsistent. The Revert right now do not save this in the list).
Monday, June 22, 2009
NewShapeModifier visual feedback changes
NewShapeModifier gives feedback for first geometry points as a polyline. This means that ellipse shape before being defined (ellipse in Naro asks three points: first two defining the major axis, the third defines the minor axis) it will show a line.
Also, the Naro sample plugin is updated to use NewShapeModifier.
Ellipse bug was almost fixed, but there is still an issue as I don't understand exactly how is the mapping between axis values and the three points. But this is the only issue in the code. There is *only* a TODO section to be written.
Also, the Naro sample plugin is updated to use NewShapeModifier.
Ellipse bug was almost fixed, but there is still an issue as I don't understand exactly how is the mapping between axis values and the three points. But this is the only issue in the code. There is *only* a TODO section to be written.
Saturday, June 20, 2009
Property grid, command line fixes and programming by contract
Because iteration is close to end, I had look on bug fixing, and the list seems smaller and smaller.
Property grid have a chance of potential crash because it scan string property instead of function name (and because we chose the same name, we did not encounter the problem, till I made a description that fails :) ).
Also there is a bug fix that is because when NaroCAD starts, the default shapes are shown as command lines adding unneeded verbosity and bogus command line list.
I had looking for a bug that "should not be there" and I found why the idea of "programming by contract" may be a solution for a class of problems. Programming by contract means that every time you will not have a corresponding parameter you will throw an exception. This is somehow a bad thing when user face it, so many programmers to not encounter problems, they do defensive programming: every time there is an argument not right, use a default, or return from function as nothing is gonna happen. The good thing of programming using "contracts" or "assertions" is that every time you throw an invalid value, is is seen to you as fast as you go.
As far as Naro is, most factories are implemented defensive, and today there was noticed a strange bug: Ellipse's property grid do nothing. I had make assumption that function do not work right. I had debugged function and seems to do all things right, also I had looked to property grid itself, some properties work fully right. I had debugged the changes in property grid, and notifications were there. The single problem was that changes were in a wrong place. We had a framework that works with contracts for Ellipse and if it were used, it would throw an exception, instead doing side effects you don't expect.
So, probably, it will be nice that even factories to work by contract, and the user who relate on them to be aware that they need to take the right thing. Is pretty bad code some like this:
IntegerInterpreter aib = label.Get<IntegerInterpreter>();
if(aib != null) ...
Probably the best code is always:
IntegerInterpreter aib = label.Get<IntegerInterpreter>();
aib.Value = 5; //throws exception
What would we do for cases that we need to check if there is a specific attribute there before accessing them?
if(label.HasAttribute<IntegerInterpreter>()) //previous code
Making things less defensive will decrease lines of code and will show more problems of your code easier. Also, will make code more expressive as you will not have to look on the code and to "skip" lines that are only checks that do almost nothing than ensure that there is really an integer there.
Property grid have a chance of potential crash because it scan string property instead of function name (and because we chose the same name, we did not encounter the problem, till I made a description that fails :) ).
Also there is a bug fix that is because when NaroCAD starts, the default shapes are shown as command lines adding unneeded verbosity and bogus command line list.
I had looking for a bug that "should not be there" and I found why the idea of "programming by contract" may be a solution for a class of problems. Programming by contract means that every time you will not have a corresponding parameter you will throw an exception. This is somehow a bad thing when user face it, so many programmers to not encounter problems, they do defensive programming: every time there is an argument not right, use a default, or return from function as nothing is gonna happen. The good thing of programming using "contracts" or "assertions" is that every time you throw an invalid value, is is seen to you as fast as you go.
As far as Naro is, most factories are implemented defensive, and today there was noticed a strange bug: Ellipse's property grid do nothing. I had make assumption that function do not work right. I had debugged function and seems to do all things right, also I had looked to property grid itself, some properties work fully right. I had debugged the changes in property grid, and notifications were there. The single problem was that changes were in a wrong place. We had a framework that works with contracts for Ellipse and if it were used, it would throw an exception, instead doing side effects you don't expect.
So, probably, it will be nice that even factories to work by contract, and the user who relate on them to be aware that they need to take the right thing. Is pretty bad code some like this:
IntegerInterpreter aib = label.Get<IntegerInterpreter>();
if(aib != null) ...
Probably the best code is always:
IntegerInterpreter aib = label.Get<IntegerInterpreter>();
aib.Value = 5; //throws exception
What would we do for cases that we need to check if there is a specific attribute there before accessing them?
if(label.HasAttribute<IntegerInterpreter>()) //previous code
Making things less defensive will decrease lines of code and will show more problems of your code easier. Also, will make code more expressive as you will not have to look on the code and to "skip" lines that are only checks that do almost nothing than ensure that there is really an integer there.
Solver improvements and fixing, Cut fixing
Worked at improving the Cut feature. Solved a crash that was appearing when the Cut was made having as reference an ellipse shape.
Started preparing at the geometric solver parallel line detection. Will work at finishing this and after that will continue improving the solver and the magic point drawing. Will also research on some classes found in OCC derived from AIS_Relation like AIS_MidPointRelation that might be useful for this task.
Will also work at fixing the Cut. Found situations when if applying two Cuts one after another if changing the color of the first Cut the model is rebuilt incorrectly.
Started preparing at the geometric solver parallel line detection. Will work at finishing this and after that will continue improving the solver and the magic point drawing. Will also research on some classes found in OCC derived from AIS_Relation like AIS_MidPointRelation that might be useful for this task.
Will also work at fixing the Cut. Found situations when if applying two Cuts one after another if changing the color of the first Cut the model is rebuilt incorrectly.
3D ellipse drawing
Worked at improving the 3D ellipse drawing. Because the code to make that needed a lot of operations I will present below the solution found:
In order to build an Geom_Ellipse it is needed to pass as parameters three elements: a gp_Ax2 that describes a right handed coordinate system, the minor radius and the major radius. Further details are that the minor radius must be smaller than major radius, the "X direction" of gp_Ax2 defines the major axis of the ellipse, the "Y direction" defines the minor axis.
In order to implement all these receiving from the user 3 points as mouse clicks I made the following:
- start calculating the major radius from the first two points:
double majorRadius = firstPoint.Distance(secondPoint)/2;
- the radius direction is built from a vector built from the first two points:
var vecX = new OCgp_Vec(firstPoint, secondPoint);
OCgp_Dir dirX = new OCgp_Dir(vecX);
- the center of the ellipse is the mid point calculated from the first two points,
- the minor radius is calculated as the distance from the third point to the line built from the first two points:
OCgp_Lin line = new OCgp_Lin(firstPoint, dirX);
double minorRadius = line.Distance(thirdPoint);
- the problem is to calculate the direction of the minor radius. It can be built making a vector from the ellipse center to the third point, this can be powerful but difficult for the user to understand it. It would be simpler to translate the third point so that the vector from the center to it would be perpendicular on the line made from the first two points.
Calculating the perpendicular can be done easily using vector geometry knowing that the result of a vector product is a vector perpendicular on the first two vectors:
var vecX = new OCgp_Vec(firstPoint, secondPoint);
// Calculate also the axis/direction of the major radus
var vecY = new OCgp_Vec(center, thirdPoint);
// We want the direction to be perpendicular on the direction of the major radius
var vecZ = vecX.Crossed(vecY);
// The minor radius direction
vecY = vecX.Crossed(vecZ);
OCgp_Dir dirY = new OCgp_Dir(vecY);
- check if the minor radius is bigger than the major radius, in this case swap the radius values and also their directions,
- build a plan from the first 3 points, get the plane normal axis, build a gp_Ax2 right handed coordinate system from it, put its location on the center of the ellipse and set the directions of the minor and major radius:
// Build a plane from the 3 points
OCgp_Pln plane = GeomUtils.BuildPlane(firstPoint, secondPoint, thirdPoint);
OCgp_Ax1 ax1 = plane.Axis();
OCgp_Ax2 ax2 = new OCgp_Ax2();
ax2.SetAxis(ax1);
// Location is the ellipse center
ax2.SetLocation(center);
// Set the radius directions, they were swapped if the minor radius was bigger than the major radius
ax2.SetXDirection(dirX);
ax2.SetYDirection(dirY);
- finally use the gp_Ax2 value, the minor radius value and the major radius value to build the ellipse:
OCGeom_Ellipse ellipse = new OCGeom_Ellipse(ax2, majorRadius, minorRadius);
In order to build an Geom_Ellipse it is needed to pass as parameters three elements: a gp_Ax2 that describes a right handed coordinate system, the minor radius and the major radius. Further details are that the minor radius must be smaller than major radius, the "X direction" of gp_Ax2 defines the major axis of the ellipse, the "Y direction" defines the minor axis.
In order to implement all these receiving from the user 3 points as mouse clicks I made the following:
- start calculating the major radius from the first two points:
double majorRadius = firstPoint.Distance(secondPoint)/2;
- the radius direction is built from a vector built from the first two points:
var vecX = new OCgp_Vec(firstPoint, secondPoint);
OCgp_Dir dirX = new OCgp_Dir(vecX);
- the center of the ellipse is the mid point calculated from the first two points,
- the minor radius is calculated as the distance from the third point to the line built from the first two points:
OCgp_Lin line = new OCgp_Lin(firstPoint, dirX);
double minorRadius = line.Distance(thirdPoint);
- the problem is to calculate the direction of the minor radius. It can be built making a vector from the ellipse center to the third point, this can be powerful but difficult for the user to understand it. It would be simpler to translate the third point so that the vector from the center to it would be perpendicular on the line made from the first two points.
Calculating the perpendicular can be done easily using vector geometry knowing that the result of a vector product is a vector perpendicular on the first two vectors:
var vecX = new OCgp_Vec(firstPoint, secondPoint);
// Calculate also the axis/direction of the major radus
var vecY = new OCgp_Vec(center, thirdPoint);
// We want the direction to be perpendicular on the direction of the major radius
var vecZ = vecX.Crossed(vecY);
// The minor radius direction
vecY = vecX.Crossed(vecZ);
OCgp_Dir dirY = new OCgp_Dir(vecY);
- check if the minor radius is bigger than the major radius, in this case swap the radius values and also their directions,
- build a plan from the first 3 points, get the plane normal axis, build a gp_Ax2 right handed coordinate system from it, put its location on the center of the ellipse and set the directions of the minor and major radius:
// Build a plane from the 3 points
OCgp_Pln plane = GeomUtils.BuildPlane(firstPoint, secondPoint, thirdPoint);
OCgp_Ax1 ax1 = plane.Axis();
OCgp_Ax2 ax2 = new OCgp_Ax2();
ax2.SetAxis(ax1);
// Location is the ellipse center
ax2.SetLocation(center);
// Set the radius directions, they were swapped if the minor radius was bigger than the major radius
ax2.SetXDirection(dirX);
ax2.SetYDirection(dirY);
- finally use the gp_Ax2 value, the minor radius value and the major radius value to build the ellipse:
OCGeom_Ellipse ellipse = new OCGeom_Ellipse(ax2, majorRadius, minorRadius);
Friday, June 19, 2009
NewShapeModifier seems to work
The NewShapeModifier class that based on a function input (it treats only Geometry, Reference/Face, Real, and Integer with default preset value) seems to work. Still there is need still to be checked on bugs and to implement some user usability features, like: if a function have three points geometry, to build at start a line, and at the third point to draw the subsequent shape.
But the good thing is that NewShapeModifier enters in the plugin public classes, so for persons that wants to extend easy Naro, they will have a chance to create fast a shape, without worry on NaroCAD's modifiers framework.
But the good thing is that NewShapeModifier enters in the plugin public classes, so for persons that wants to extend easy Naro, they will have a chance to create fast a shape, without worry on NaroCAD's modifiers framework.
Thursday, June 18, 2009
Extra features and fixes
NaroCAD data model was for sure powerful. It can store almost everything, it propagates data, it is extensible, persistent (can be saved and restored from Xml) and is feature wise a good use of C# 2.0 features as generics constraints, which makes more nice to be used at least than a C++ code.
This means that you can add easy to NaroCAD new extra features as CAM/CAE attributes, constraints, etc.
Sounds great, but his happen to be only on model level. There is always a need to express this at the user level. The most known case is: Property Grid which takes the current shape and gives a custom interface to it. Right now the Property Grid code is refactored to be able to add for any custom attribute a custom Property Grid section.
Right now there is a new section named: Shape that is attached to NamedShape attribute, but it does the job well and proving this concept is working.
Extrude generated using the NewShapeModifer framework is almost working, but I have still to fix bugs to it to behave like the previous code. Like: changing color to red when is live generated, to add second extrude after first one, etc.
Also, I had fixed two bugs: every command line that is executed did not update the view, and there was a case when save/load to XML did not get a reference to the document and make it crash.
This means that you can add easy to NaroCAD new extra features as CAM/CAE attributes, constraints, etc.
Sounds great, but his happen to be only on model level. There is always a need to express this at the user level. The most known case is: Property Grid which takes the current shape and gives a custom interface to it. Right now the Property Grid code is refactored to be able to add for any custom attribute a custom Property Grid section.
Right now there is a new section named: Shape that is attached to NamedShape attribute, but it does the job well and proving this concept is working.
Extrude generated using the NewShapeModifer framework is almost working, but I have still to fix bugs to it to behave like the previous code. Like: changing color to red when is live generated, to add second extrude after first one, etc.
Also, I had fixed two bugs: every command line that is executed did not update the view, and there was a case when save/load to XML did not get a reference to the document and make it crash.
Parametric modeling Cut, shape removal
Worked at fixing the Cut functionality, it started to cover well situations when it is invoked by a parametric modeling propagation. When Cut is applied on a scene it stores the objects affected by the operation and later if Cut is modified it is applied again on the objects stored. Objects added after the Cut or not affected when it was applied for the first time will not be affected later.
Implemented a first version of Delete. If a shape is selected and the Del key is pressed the shape is removed. Will finalize it tomorrow by implementing a modifier for it, task estimated to take 1-2 hours.
Will also work at improving the geometric solver and the magic point drawing.
Implemented a first version of Delete. If a shape is selected and the Del key is pressed the shape is removed. Will finalize it tomorrow by implementing a modifier for it, task estimated to take 1-2 hours.
Will also work at improving the geometric solver and the magic point drawing.
Wednesday, June 17, 2009
Again fixes and a benchmark
I had made some fixes that was mainly related with design of yesterday. I had almost no time to continue adnotation adding.
I wanted to check how much NaroAD it scales up. Means how many distinct shapes can you work with and what is the associated overhead. I found that first of all Naro is fairly fast and in a lot of cases is enough fast to work with complex scenes. Also, NaroCAD is built on top of OpenCascade which may be itself slow in the tests we've made them.
What was the benchmark about? To add continuously 10.000 lines to NaroCAD scene and see how it behaves. So I had four cases: 0 to 10.000 shapes (to be more fair, from 3 shapes), 10.000 to 20.000 shapes, etc.
Here are the results
This specific benchmark shows that it will take longer and longer to add the same amount of shapes. Also, Undo step processing itself may take 1/5 of time and grows as the scene increase in size.
Also, for persons that wants to count everything, at 40k primitives NaroCAD uses 550M of RAM and have completely define the primitives in both visual and persistent way. Means you may have a document with 40k small shapes using XP and 1G of RAM.
Should you be worry on this performance hit on high level primitive count? I really believe that you should not. But if you think that performance matter on you, the biggest thing you should do is to optimize OpenCascade code as only to show 10 K lines, is a hit of performance of OpenCasade visualization level. Also, if for you that performance scaling is an issue, you may work on more documents in NaroCAD, and at the end combine them. Also, even in the slowest part of benchmark, to add a shape at over 30.000 shapes already drawn, from defining it to add it to OpenCascade/OpenGl visualization layer, take 6.5 ms (on average). Is practically no performance hit for an user that works with such a high scene complexity.
There is only a downside and this is by processing Undo, that may take seconds to make a diff correctly. Probably only Undo should be optimized in future, but in regular usage, till 1000 shapes, you will be hardly notice it.
The part I found pretty hard is to work with more than 100 shapes in NaroCAD, let alone 10000 shapes. at least from tree. Probably automatically numbering shapes will be a nice feature to be seen. Also would be nice to filter shapes from tree. Sounds pretty odd that when are created from a script 100 lines, to not know on which line to click.
I wanted to check how much NaroAD it scales up. Means how many distinct shapes can you work with and what is the associated overhead. I found that first of all Naro is fairly fast and in a lot of cases is enough fast to work with complex scenes. Also, NaroCAD is built on top of OpenCascade which may be itself slow in the tests we've made them.
What was the benchmark about? To add continuously 10.000 lines to NaroCAD scene and see how it behaves. So I had four cases: 0 to 10.000 shapes (to be more fair, from 3 shapes), 10.000 to 20.000 shapes, etc.
Here are the results
This specific benchmark shows that it will take longer and longer to add the same amount of shapes. Also, Undo step processing itself may take 1/5 of time and grows as the scene increase in size.
Also, for persons that wants to count everything, at 40k primitives NaroCAD uses 550M of RAM and have completely define the primitives in both visual and persistent way. Means you may have a document with 40k small shapes using XP and 1G of RAM.
Should you be worry on this performance hit on high level primitive count? I really believe that you should not. But if you think that performance matter on you, the biggest thing you should do is to optimize OpenCascade code as only to show 10 K lines, is a hit of performance of OpenCasade visualization level. Also, if for you that performance scaling is an issue, you may work on more documents in NaroCAD, and at the end combine them. Also, even in the slowest part of benchmark, to add a shape at over 30.000 shapes already drawn, from defining it to add it to OpenCascade/OpenGl visualization layer, take 6.5 ms (on average). Is practically no performance hit for an user that works with such a high scene complexity.
There is only a downside and this is by processing Undo, that may take seconds to make a diff correctly. Probably only Undo should be optimized in future, but in regular usage, till 1000 shapes, you will be hardly notice it.
The part I found pretty hard is to work with more than 100 shapes in NaroCAD, let alone 10000 shapes. at least from tree. Probably automatically numbering shapes will be a nice feature to be seen. Also would be nice to filter shapes from tree. Sounds pretty odd that when are created from a script 100 lines, to not know on which line to click.
Parametric modeling Cut
Added parametric functionality at Cut so that if the reference shape that cuts through objects is modified the final Cut shape is regenerated. Currently Cut stores the list of objects affected by the Cut; will modify the current functionality (Cut is applied on all visible objects from the scene) to the functionality that if Cut is modified only the referenced objects will be modified and objects added later even if located on the Cut direction will not be altered by Cut regeneration, task estimated to take 1-2 hours. Will also investigate why the Cut Boolean operation gives result when it shouldn't.
Tuesday, June 16, 2009
Love is all around ... in fixes
Based on work of the last weekend and fixes of today, Line3D visual action can be rewritten in 5 lines of code.
public class AlternateLine : NewShapeModifier
{
public AlternateLine(WorkItem workItem)
: base(ModifierNames.AlternateLine, "Line", workItem) { }
}
But the NewShapeModifier base class have some internal limitations that was based on already existing limitations of Actions/Inputs framework in NaroCAD. One of them was that it was not possible to add inputs live. Right now you can, but the bad thing is that you cannot remove them live.
Why is needed to add/remove live inputs?
Firstly we have to understand how Naro's actions framework works. In principle, an action is a button that change the current document/modeller in a specific state. Because this state should be extensible from one point, and to avoid tight coupling, any action may require resources, named inputs, that give to this action what it needs, like (but not limited to): document, OpenCascade context, OpenCascade view, tree view, property view, a current face, a 3d coordinate that is triggered on mouse move, etc.
The NewShapeModifier tries to implement the following thing: for a given shape, that is defined by it's function name, to create an action that do all internal stuff (like document life cycle, connecting to various inputs) internally to populate function's dependency. And at the end to create this shape in current document. This part of code take in case of Line3D more than 150 lines and is error prone. But NewShapeModifier needs to open different inputs based on different shapes, so this is the reason it was needed to be possible to add dynamically new inputs.
If NewShapeModifier will work will make trivial at least for simple shapes to add the corresponding action. And it will work from scratch, with (almost) no extra setup.
I will continue to make possible making real annotations to dependencies and based on this Extrude action (which is not a trivial action as was line3D) to be possible.
public class AlternateLine : NewShapeModifier
{
public AlternateLine(WorkItem workItem)
: base(ModifierNames.AlternateLine, "Line", workItem) { }
}
But the NewShapeModifier base class have some internal limitations that was based on already existing limitations of Actions/Inputs framework in NaroCAD. One of them was that it was not possible to add inputs live. Right now you can, but the bad thing is that you cannot remove them live.
Why is needed to add/remove live inputs?
Firstly we have to understand how Naro's actions framework works. In principle, an action is a button that change the current document/modeller in a specific state. Because this state should be extensible from one point, and to avoid tight coupling, any action may require resources, named inputs, that give to this action what it needs, like (but not limited to): document, OpenCascade context, OpenCascade view, tree view, property view, a current face, a 3d coordinate that is triggered on mouse move, etc.
The NewShapeModifier tries to implement the following thing: for a given shape, that is defined by it's function name, to create an action that do all internal stuff (like document life cycle, connecting to various inputs) internally to populate function's dependency. And at the end to create this shape in current document. This part of code take in case of Line3D more than 150 lines and is error prone. But NewShapeModifier needs to open different inputs based on different shapes, so this is the reason it was needed to be possible to add dynamically new inputs.
If NewShapeModifier will work will make trivial at least for simple shapes to add the corresponding action. And it will work from scratch, with (almost) no extra setup.
I will continue to make possible making real annotations to dependencies and based on this Extrude action (which is not a trivial action as was line3D) to be possible.
Monday, June 15, 2009
Fixes on update issues
There are small fixes over the actions. Undo/Redo actions hardcoded till now the update code (it updates only the current view). The load from any file did not happen to update the tree view and the OpenCascade view itself. Right now both actions do it using notifications. These actions are a bit refactored to be set in categories.
Last week I had worked to an action that creates automatically given inputs based on dependencies. Because of dependency refactor I had introduced a bug which makes this action to fail. Right now is fixed.
Also, Undo and Redo are made right now as actions. This means mainly that are not hardcoded in the ModuleViewContoller component from part modeling.
Last week I had worked to an action that creates automatically given inputs based on dependencies. Because of dependency refactor I had introduced a bug which makes this action to fail. Right now is fixed.
Also, Undo and Redo are made right now as actions. This means mainly that are not hardcoded in the ModuleViewContoller component from part modeling.
Saturday, June 13, 2009
Load / Save to XML works
A long standing bug was Naro was that XML loading crash abruptly and was seemingly a such hidden cause that was not solved in more than some days. The reason was pretty hidden in itself, as functions override one attribute (named: "Name") that was used as default attribute in serialization. Thus, right now works to load a Naro XML formatted document. I will work for other standing bugs.
Cut started working
Succeeded to make the Cut work. Now it cuts through all, will add in the property grid also the option to Cut with a depth. The screenshot contains an Extrusion on an ellipse and with a Cut on them.
Will continue fixing bugs at Extrude, improving the magic points and fixing Cut.
The Cut through all is made like the following:
// Make a prism that will cut through all objects
OCBRepPrimAPI_MakePrism cutPrism = new OCBRepPrimAPI_MakePrism(cuttingShape, vec, false, true);
OCTopoDS_Shape cutPrismShape = cutPrism.Shape();
// On all shapes from the scene apply Cut
OCBRepAlgoAPI_Cut cut = new OCBRepAlgoAPI_Cut(topoShape, cutPrismShape);
OCTopoDS_Shape shapeCut = cut.Shape();
if (!shapeCut.IsNull())
{
// Add the result at the compund shape
shapeBuilder.Add(resShape, shapeCut);
}
The code to make the result shape like a compund:
OCTopoDS_Compound compoundShape = new OCTopoDS_Compound();
OCBRep_Builder shapeBuilder = new OCBRep_Builder();
shapeBuilder.MakeCompound(compoundShape);
OCTopoDS_Shape resShape = compoundShape as OCTopoDS_Shape;
// Add each shape cut at the compound shape
shapeBuilder.Add(resShape, shapeCut);
Friday, June 12, 2009
Under the hood updates
There is made an action that builds for Line (at least for geometry that dependencies does not need extra work to be enable) to be made based on the function dependency.
Also, dependencies are changed and simplified and they are changed from SortedDictionary to List.
I had integrated bxtrx's code for save to Step and seems working.
Cut needs an extra dependency but I have no proper solution. This dependency need to be notified on scene change. The issue is that a lot of changes are happening which can trigger the event and I have no limit when it starts and when it ends. If will be a parametric change, cut may be generated for every parametric change, which is not wanted. Probably some changes will need a guard pattern used to minimize the regenerating calls. I will still have to think to a proper design to do it. Also, very probably it will be needed an extra attribute in Naro Data tree.
I will continue tomorrow to think to a proper design regarding the changes notifications and with bug fixing. I have still situations when load form XML fails and I will focus on that.
Also, dependencies are changed and simplified and they are changed from SortedDictionary to List.
I had integrated bxtrx's code for save to Step and seems working.
Cut needs an extra dependency but I have no proper solution. This dependency need to be notified on scene change. The issue is that a lot of changes are happening which can trigger the event and I have no limit when it starts and when it ends. If will be a parametric change, cut may be generated for every parametric change, which is not wanted. Probably some changes will need a guard pattern used to minimize the regenerating calls. I will still have to think to a proper design to do it. Also, very probably it will be needed an extra attribute in Naro Data tree.
I will continue tomorrow to think to a proper design regarding the changes notifications and with bug fixing. I have still situations when load form XML fails and I will focus on that.
3D ellipse, Cut feature
Implemented the 3D ellipse shape drawing, uploaded the code on SVN.
Almost finished implementing the Cut feature. Made the infrastructure, the modifier, the event handler so that it can be called from command line. Planning to make two Cut possibilities: through all and to depth. Tomorrow hope to make it working in 1-3 hours.
Almost finished implementing the Cut feature. Made the infrastructure, the modifier, the event handler so that it can be called from command line. Planning to make two Cut possibilities: through all and to depth. Tomorrow hope to make it working in 1-3 hours.
Thursday, June 11, 2009
STEP writing
Fixed the STEPControl_Writer.Write() method. Rebuilt the wrappers and uploaded on SVN.
The following code dumps a box on disk:
OCSTEPControl_Writer aWriter = new OCSTEPControl_Writer();
OCTopoDS_Shape shape = new OCBRepPrimAPI_MakeBox(200.0, 150.0, 100.0).Shape();
aWriter.Transfer(shape, OCSTEPControl_StepModelType.STEPControl_ShellBasedSurfaceModel, true);
OCIFSelect_ReturnStatus status = aWriter.Write("C:/sharptest.step");
Implemented by hand the wrapper for the method, solved the problem by allocating a char* buffer where copied the String passed from C#, with this buffer called the native method and released the buffer at the end. Previously the code was just pinning and passing the internal pointer to String:
Standard_CString OCConverter::StringToStandardCString(System::String^ text)
{
pin_ptr textPtr = PtrToStringChars(text);
return TCollection_AsciiString((Standard_ExtString)textPtr).ToCString();
} // OCConverter::ToStandardCString
This method is used at all the String to char* conversions. Will have to think if this functionality is ok and why in the Write() case the internal pointer was overridden when memory was requested from the OpenCascade memory pool by some other object.
The following code dumps a box on disk:
OCSTEPControl_Writer aWriter = new OCSTEPControl_Writer();
OCTopoDS_Shape shape = new OCBRepPrimAPI_MakeBox(200.0, 150.0, 100.0).Shape();
aWriter.Transfer(shape, OCSTEPControl_StepModelType.STEPControl_ShellBasedSurfaceModel, true);
OCIFSelect_ReturnStatus status = aWriter.Write("C:/sharptest.step");
Implemented by hand the wrapper for the method, solved the problem by allocating a char* buffer where copied the String passed from C#, with this buffer called the native method and released the buffer at the end. Previously the code was just pinning and passing the internal pointer to String:
Standard_CString OCConverter::StringToStandardCString(System::String^ text)
{
pin_ptr
return TCollection_AsciiString((Standard_ExtString)textPtr).ToCString();
} // OCConverter::ToStandardCString
This method is used at all the String to char* conversions. Will have to think if this functionality is ok and why in the Write() case the internal pointer was overridden when memory was requested from the OpenCascade memory pool by some other object.
Actions review - close to finish
Actions that creates a new shape will be very easy to create a new action. It mainly need to know the function name and if you need to define some fields as default and that is all.
The code is setup but needs "love" means that need to be fixed and cleaned up greatly. I haven't courage to commit it yet, but will come soon.
The code is setup but needs "love" means that need to be fixed and cleaned up greatly. I haven't courage to commit it yet, but will come soon.
Tuesday, June 9, 2009
Actions Code Review (part II)
Going back reviewing code, the code regarding dependencies reduces greatly. This is made by making an analisis of what are needed and how can be used externally. The code will make a clean fundation for making actions to operate much easier with function's dependencies. The code reduces from around 400 lines to 250 and the dependency logic itself reduces to almost a half of code. This is done because dependencies in the past were stored as a tree, which makes the code more complex both to operate and to navigate.
As of tomorrow I will focus on solving all regressions (seems to be none to the moment) and to continue make generating almost automatically of one action that starting from a function's dependency and some annotations to make a complex action as the extrude to work. This will mean that at least for plugins writers, if they will need a pretty new shape, will not need to take in account the document definition. Also, the code of view will automatically be updated. This is all theory, but I already wait to make it happen.
As of tomorrow I will focus on solving all regressions (seems to be none to the moment) and to continue make generating almost automatically of one action that starting from a function's dependency and some annotations to make a complex action as the extrude to work. This will mean that at least for plugins writers, if they will need a pretty new shape, will not need to take in account the document definition. Also, the code of view will automatically be updated. This is all theory, but I already wait to make it happen.
Iteration 0.0.12 closed
Closed Iteration 0.0.12. Among the tasks made during this iteration are:
- implemented command line at the application. Everything that is drawn with the mouse appears also on the command line. The history of commands can be saved and executed later. Useful for making test files and good also as precision drawing helpers,
- implemented a draw line plugin that duplicates the draw line functionality, the plugin architecture will be improved after refactoring the pipes used for the actions,
- modified the extrude to follow the mouse when drawing, useful that the mouse events will be passed through the geometric solver,
- implemented magic points: when the mouse moves over a vertex or the segment midpoint the point is emphasized. Added in the geometric solver code that also detects coplanar points, also the Extrude can be made until coplanar with a point or until it meets a magic point but this functionality needs improvements as it doesn't work very well,
- started working at saving and loading the application internal data as an XML like representation, started implementing Brep and STEP import and export functionality,
- added STEP wrappers in the wrappers library, an issue that STEP writing doesn't work needs to be solved.
For the next Iteration (0.0.13) the scheduled tasks are:
- Improve the actual Actions/Modifiers implemented with pipes to have the inputs they need as dependencies with that being implemented on a higher abstraction level; this will be used also at improving the functionality exposed to plugin developers,
- Finish save, load, export STEP or Brep, import STEP and Brep,
- Improve the magic point detection,
- Stabilize the current functionality, bug fixing,
- Add an Ellipse drawing shape,
- Make the Cut and Fillet previous functionality work properly with the new code.
In order to have a release candidate the functionality needed to be implemented:
- Save, Load, Import, Export, under development, will be finished on the current iteration,
- Installer, automatic updater, implemented,
- Basic shape drawing: line and rectangle is implemented, ellipse will be implemented in the current iteration,
- Features: Extrude implemented, Fillet implemented and needs to be refined, Cut to port the previous code to the current application,
- Property table for the models, implemented,
- Magic points, implemented, needs improvements,
- Undo redo, implemented,
- Command line, command history saving and executing, implemented,
- Plugin support, implemented, needs to be improved,
- User manual, documentation for developers generation, implemented something in the past, needs update,
Other functionality that will be implemented in the future: constraints, support for drawn object library, 3d shape drawing, combine parts into a bigger model, export drawings, having template drawings.
- implemented command line at the application. Everything that is drawn with the mouse appears also on the command line. The history of commands can be saved and executed later. Useful for making test files and good also as precision drawing helpers,
- implemented a draw line plugin that duplicates the draw line functionality, the plugin architecture will be improved after refactoring the pipes used for the actions,
- modified the extrude to follow the mouse when drawing, useful that the mouse events will be passed through the geometric solver,
- implemented magic points: when the mouse moves over a vertex or the segment midpoint the point is emphasized. Added in the geometric solver code that also detects coplanar points, also the Extrude can be made until coplanar with a point or until it meets a magic point but this functionality needs improvements as it doesn't work very well,
- started working at saving and loading the application internal data as an XML like representation, started implementing Brep and STEP import and export functionality,
- added STEP wrappers in the wrappers library, an issue that STEP writing doesn't work needs to be solved.
For the next Iteration (0.0.13) the scheduled tasks are:
- Improve the actual Actions/Modifiers implemented with pipes to have the inputs they need as dependencies with that being implemented on a higher abstraction level; this will be used also at improving the functionality exposed to plugin developers,
- Finish save, load, export STEP or Brep, import STEP and Brep,
- Improve the magic point detection,
- Stabilize the current functionality, bug fixing,
- Add an Ellipse drawing shape,
- Make the Cut and Fillet previous functionality work properly with the new code.
In order to have a release candidate the functionality needed to be implemented:
- Save, Load, Import, Export, under development, will be finished on the current iteration,
- Installer, automatic updater, implemented,
- Basic shape drawing: line and rectangle is implemented, ellipse will be implemented in the current iteration,
- Features: Extrude implemented, Fillet implemented and needs to be refined, Cut to port the previous code to the current application,
- Property table for the models, implemented,
- Magic points, implemented, needs improvements,
- Undo redo, implemented,
- Command line, command history saving and executing, implemented,
- Plugin support, implemented, needs to be improved,
- User manual, documentation for developers generation, implemented something in the past, needs update,
Other functionality that will be implemented in the future: constraints, support for drawn object library, 3d shape drawing, combine parts into a bigger model, export drawings, having template drawings.
STEP saving with wrappers
Because the STEP file writing using the wrappers fails, made the same test using C++:
TopoDS_Shape B1 = BRepPrimAPI_MakeBox (200.,150.,100.);
STEPControl_Writer aWriter;
aWriter.Transfer(B1, STEPControl_ShellBasedSurfaceModel);
IFSelect_ReturnStatus status = aWriter.Write("C:/mfctest.step");
The C++ code works well and saves the box shape on the file. The same code made with .Net wrappers fails and nothing is written on disk:
OCSTEPControl_Writer aWriter = new OCSTEPControl_Writer();
OCTopoDS_Shape shape = new OCBRepPrimAPI_MakeBox(200.0, 150.0, 100.0).Shape();
aWriter.Transfer(shape, OCSTEPControl_StepModelType.STEPControl_ShellBasedSurfaceModel, true);
OCIFSelect_ReturnStatus status = aWriter.Write("C:/sharptest.step");
The generated wrapper code seems ok, no exceptions are generated. Will continue investigation on this tomorrow by debugging using WinDbg on OpenCascade built in debug mode to find the native line of code which fails.
TopoDS_Shape B1 = BRepPrimAPI_MakeBox (200.,150.,100.);
STEPControl_Writer aWriter;
aWriter.Transfer(B1, STEPControl_ShellBasedSurfaceModel);
IFSelect_ReturnStatus status = aWriter.Write("C:/mfctest.step");
The C++ code works well and saves the box shape on the file. The same code made with .Net wrappers fails and nothing is written on disk:
OCSTEPControl_Writer aWriter = new OCSTEPControl_Writer();
OCTopoDS_Shape shape = new OCBRepPrimAPI_MakeBox(200.0, 150.0, 100.0).Shape();
aWriter.Transfer(shape, OCSTEPControl_StepModelType.STEPControl_ShellBasedSurfaceModel, true);
OCIFSelect_ReturnStatus status = aWriter.Write("C:/sharptest.step");
The generated wrapper code seems ok, no exceptions are generated. Will continue investigation on this tomorrow by debugging using WinDbg on OpenCascade built in debug mode to find the native line of code which fails.
Monday, June 8, 2009
Actions code review (part I)
NaroCAD code have right now multiple layers which clearly separates the roles.
To define a simple shape (like a line), you should have clear the following things:
- dependency (two points in 3D)
- a build shape code named function
- from view point you should define a modifier (named Action) that gets inputs like: application document, mouse events, etc. and builds from it a function and populate it's events.
So far so good, but this makes the code for actions to be error prone because it have multiple interactions with document, document items, mouse inputs, it should notify using SCSF events the interpreter,
An action as Extrude is pretty complicated right now: it should create a subshape face if needed, it should manage the document lifecycle, it should update the object shape.
This makes at least for shape based functions to try to simplify as much as possible the code. This task is linked with posibility to define in a simple way editable things.
Reviewing it makes me to think at least that at least most of actions can be built back from dependencies and some adnotations. I will try to complete this task tomorrow and try to find a clearer code level at the modifiers code. This will combine with plugins code that will make others to add in a very easy fashion support for other shapes.
To define a simple shape (like a line), you should have clear the following things:
- dependency (two points in 3D)
- a build shape code named function
- from view point you should define a modifier (named Action) that gets inputs like: application document, mouse events, etc. and builds from it a function and populate it's events.
So far so good, but this makes the code for actions to be error prone because it have multiple interactions with document, document items, mouse inputs, it should notify using SCSF events the interpreter,
An action as Extrude is pretty complicated right now: it should create a subshape face if needed, it should manage the document lifecycle, it should update the object shape.
This makes at least for shape based functions to try to simplify as much as possible the code. This task is linked with posibility to define in a simple way editable things.
Reviewing it makes me to think at least that at least most of actions can be built back from dependencies and some adnotations. I will try to complete this task tomorrow and try to find a clearer code level at the modifiers code. This will combine with plugins code that will make others to add in a very easy fashion support for other shapes.
Saturday, June 6, 2009
Still save/load
Save load on XML still does not work. The Step wrappers are used to operate with Step format (there it seem that is an error on working with Step format).
Is fixed an interpreter issue about saving files, that last command is executed twice and that commands appear twice on screen.
Because saving/loading tasks took too long, I will try to compensate this doing other things to be a visible progress in other ways, but more about this in the next iteration.
Is fixed an interpreter issue about saving files, that last command is executed twice and that commands appear twice on screen.
Because saving/loading tasks took too long, I will try to compensate this doing other things to be a visible progress in other ways, but more about this in the next iteration.
Friday, June 5, 2009
STEP wrappers
Thanks to one of our contributors we received wrappers for STEP functionality that are now included in the wrapper package. The newly compiled OCWrappers.dll is uploaded on SVN on the \trunk\wrappers\builds\release\ and also on the \trunk\narocad\Lib\. The Naro seems to work well with the new package.
Thanks again for the help to the user "entery".
Made some test code to see how it works, succeeded to load and display successfully the "screw.step" sample file from OpenCascade. When tried to write back the same shape it didn't work, Transfer() succeeded but Write(fileName) failed. It shouldn't be a wrapper problem, but this can be tested only by verifying the code against the same code implemented in C++.
Thanks again for the help to the user "entery".
Made some test code to see how it works, succeeded to load and display successfully the "screw.step" sample file from OpenCascade. When tried to write back the same shape it didn't work, Transfer() succeeded but Write(fileName) failed. It shouldn't be a wrapper problem, but this can be tested only by verifying the code against the same code implemented in C++.
Added also a test method in the test codes STEPLoadingTest():
// Load a STEP file and display it
OCSTEPControl_Reader aReader = new OCSTEPControl_Reader();
String fileName = @"c:\screw.step";
OCIFSelect_ReturnStatus status = aReader.ReadFile(fileName);
Assert.IsTrue(status == OCIFSelect_ReturnStatus.IFSelect_RetDone, "Invalid return status");
aReader.WS().MapReader().SetTraceLevel(2); // increase default trace level
bool failsonly = false;
aReader.PrintCheckLoad(failsonly, OCIFSelect_PrintCount.IFSelect_ItemsByEntity);
// Root transfers
int nbr = aReader.NbRootsForTransfer();
aReader.PrintCheckTransfer(failsonly, OCIFSelect_PrintCount.IFSelect_ItemsByEntity);
for (int n = 1; n <= nbr; n++)
{
bool ok = aReader.TransferRoot(n);
} // Collecting resulting entities
int nbs = aReader.NbShapes();
Assert.IsTrue(nbs > 0, "no shapes loaded");
OCTopTools_HSequenceOfShape aSequence = new OCTopTools_HSequenceOfShape();
for (int i = 1; i <= nbs; i++)
{
aSequence.Append(aReader.Shape(i));
}
OCAIS_Shape aisShape;
for (int i = 1; i <= aSequence.Length(); i++)
{
aisShape = new OCAIS_Shape(aSequence.Value(i));
_context3d.SetDisplayMode(aisShape, 1, false);
_context3d.Display(aisShape, false);
_context3d.SetCurrentObject(aisShape, false);
}
_context3d.UpdateCurrentViewer();
_view3d.FitAll(0.01, false, true); Thread.Sleep(10000);
_context3d.RemoveAll(true);
OCSTEPControl_Writer aWriter = new OCSTEPControl_Writer();
for (int i = 1; i <= aSequence.Length(); i++)
{
status = aWriter.Transfer(aSequence.Value(i), OCSTEPControl_StepModelType.STEPControl_ShellBasedSurfaceModel, true);
Assert.IsTrue(status == OCIFSelect_ReturnStatus.IFSelect_RetDone, "Invalid return status");
}
String outputFileName = @"c:\test.step";
status = aWriter.Write(outputFileName);
Assert.IsTrue(status == OCIFSelect_ReturnStatus.IFSelect_RetDone, "Invalid return status");
// Load a STEP file and display it
OCSTEPControl_Reader aReader = new OCSTEPControl_Reader();
String fileName = @"c:\screw.step";
OCIFSelect_ReturnStatus status = aReader.ReadFile(fileName);
Assert.IsTrue(status == OCIFSelect_ReturnStatus.IFSelect_RetDone, "Invalid return status");
aReader.WS().MapReader().SetTraceLevel(2); // increase default trace level
bool failsonly = false;
aReader.PrintCheckLoad(failsonly, OCIFSelect_PrintCount.IFSelect_ItemsByEntity);
// Root transfers
int nbr = aReader.NbRootsForTransfer();
aReader.PrintCheckTransfer(failsonly, OCIFSelect_PrintCount.IFSelect_ItemsByEntity);
for (int n = 1; n <= nbr; n++)
{
bool ok = aReader.TransferRoot(n);
} // Collecting resulting entities
int nbs = aReader.NbShapes();
Assert.IsTrue(nbs > 0, "no shapes loaded");
OCTopTools_HSequenceOfShape aSequence = new OCTopTools_HSequenceOfShape();
for (int i = 1; i <= nbs; i++)
{
aSequence.Append(aReader.Shape(i));
}
OCAIS_Shape aisShape;
for (int i = 1; i <= aSequence.Length(); i++)
{
aisShape = new OCAIS_Shape(aSequence.Value(i));
_context3d.SetDisplayMode(aisShape, 1, false);
_context3d.Display(aisShape, false);
_context3d.SetCurrentObject(aisShape, false);
}
_context3d.UpdateCurrentViewer();
_view3d.FitAll(0.01, false, true); Thread.Sleep(10000);
_context3d.RemoveAll(true);
OCSTEPControl_Writer aWriter = new OCSTEPControl_Writer();
for (int i = 1; i <= aSequence.Length(); i++)
{
status = aWriter.Transfer(aSequence.Value(i), OCSTEPControl_StepModelType.STEPControl_ShellBasedSurfaceModel, true);
Assert.IsTrue(status == OCIFSelect_ReturnStatus.IFSelect_RetDone, "Invalid return status");
}
String outputFileName = @"c:\test.step";
status = aWriter.Write(outputFileName);
Assert.IsTrue(status == OCIFSelect_ReturnStatus.IFSelect_RetDone, "Invalid return status");
Thursday, June 4, 2009
Plugins, improved geometric solver
Implemented the first Naro plugin that duplicates the line drawing functionality and it seems to work well.
Implemented Extrude drawing that follows the mouse move but here one more problem has to be solved: could not detect when the mouse moves under the face on which the extrusion is made. The improvement is that the Extrusion goes through the geometric solver so the extrusion height can be made to a magic point.
Improved the pipe that converts 2D mouse events to the 3d OpenCascade space so that beside generating points into a selected plane it can also generate 3D points when no plane is selected. Also extended the utilities library with a few new useful functions.
Will continue working at finishing the the functionality scheduled for the current iteration.
Implemented Extrude drawing that follows the mouse move but here one more problem has to be solved: could not detect when the mouse moves under the face on which the extrusion is made. The improvement is that the Extrusion goes through the geometric solver so the extrusion height can be made to a magic point.
Improved the pipe that converts 2D mouse events to the 3d OpenCascade space so that beside generating points into a selected plane it can also generate 3D points when no plane is selected. Also extended the utilities library with a few new useful functions.
Will continue working at finishing the the functionality scheduled for the current iteration.
Wednesday, June 3, 2009
Importing external BREP shapes in NaroCAD works
NaroCAD can work with BREP shapes right now (right now only to import) but rest of others operations will follow.
Which kind of format BREP? BREP stands from Boundary Representation and it is like Step format. Is a format implemented in OpenCascade and using the Import/Export application provided with OpenCascade you can convert any formats like: STEP or STL to BREP.
The imported shapes can be as complex as OpenCascade can store, still the shape as it is, at NaroCAD level it does not offer the high level attributes but only dumb geometry.
I would plan to finish today saving to BREP and save/load using Xml of Naro internal data.
So if you will create a shape in NaroCAD and you will want to import it to other CAD software, you may use BREP. If you will need some information attached to a specific shape, you may use Xml.
Which kind of format BREP? BREP stands from Boundary Representation and it is like Step format. Is a format implemented in OpenCascade and using the Import/Export application provided with OpenCascade you can convert any formats like: STEP or STL to BREP.
The imported shapes can be as complex as OpenCascade can store, still the shape as it is, at NaroCAD level it does not offer the high level attributes but only dumb geometry.
I would plan to finish today saving to BREP and save/load using Xml of Naro internal data.
So if you will create a shape in NaroCAD and you will want to import it to other CAD software, you may use BREP. If you will need some information attached to a specific shape, you may use Xml.
Tuesday, June 2, 2009
Extrusion magic points
Added code so that when making an extrude the magic points that describe it are added to the geometric solver. Lines and rectangles can be drawn on the faces of an extrude using magic points. Also the planes representing the extrusion faces are added in the solver and will be used for coplanar detection.
Fixed bugs: fixed the bug that extrusions couldn't be made on drawn rectangles, solved the rectangle drawing bug (the rectangle was disappearing after drawing), fixed a face iteration on solids code.
Started working at implementing an Extrude that follows the mouse, currently the extrusion height is calculated as the distance that the mouse moved, when the extrude will follow the mouse it will pass through solver so that Extrusions will be made using magic points.
Monday, June 1, 2009
Save and load... and a question...
It seems that Save and Load to not be an easy task for me at least.
Question: if you would like use an new CAD application, like Naro, which format would you prefer to be used for save/restore the file in application?
Probably would you prefer (Boundary Representation like) STEP one or OCAF one?
STEP one is great but save too few things. Also as is right now is pretty hard to import in Naro as Naro works with high level primitives. So, information like: layers, constraints (not yet implemented), CAM parameters, etc. , even combining of some complex shapes (we can define an extrude as a base of another extrude using a referencing shape named subshape) will generate extra geometry that is not possible to save to Step. Also, all parametric propagation will not be properly restored. (at least from my understanding of what Step can save)
OCAF in itself is a format that stores data. Is somehow similar with XML. So converting the Naro tree to OCAF and save it, will bring the advantage of saving full attributes of Naro (Naro can be extended to save almost everything, at least by design) but no other application will know how to import them.
Also, considering that you would prefer OCAF, why OCAF and not XML? XML at least can be read by all browsers, text editors with syntax highlighting (and why not by Notepad?) and any wide used language (C using libxml2, C++, Java, C#, Python, Delphi) and can be somehow easily generated by other users and also can be easily extracted some information without having dependencies to OpenCascade library.
Still blocked to answer on this question from one side, and not knowing how to make it work (mostly the Step solution) I start doing the insertion of infrastructure code and letting blank only the save/load part. There are two new inputs for getting a file from disk drive and two actions that have almost no code.
So if you have any idea, drop a line...
Question: if you would like use an new CAD application, like Naro, which format would you prefer to be used for save/restore the file in application?
Probably would you prefer (Boundary Representation like) STEP one or OCAF one?
STEP one is great but save too few things. Also as is right now is pretty hard to import in Naro as Naro works with high level primitives. So, information like: layers, constraints (not yet implemented), CAM parameters, etc. , even combining of some complex shapes (we can define an extrude as a base of another extrude using a referencing shape named subshape) will generate extra geometry that is not possible to save to Step. Also, all parametric propagation will not be properly restored. (at least from my understanding of what Step can save)
OCAF in itself is a format that stores data. Is somehow similar with XML. So converting the Naro tree to OCAF and save it, will bring the advantage of saving full attributes of Naro (Naro can be extended to save almost everything, at least by design) but no other application will know how to import them.
Also, considering that you would prefer OCAF, why OCAF and not XML? XML at least can be read by all browsers, text editors with syntax highlighting (and why not by Notepad?) and any wide used language (C using libxml2, C++, Java, C#, Python, Delphi) and can be somehow easily generated by other users and also can be easily extracted some information without having dependencies to OpenCascade library.
Still blocked to answer on this question from one side, and not knowing how to make it work (mostly the Step solution) I start doing the insertion of infrastructure code and letting blank only the save/load part. There are two new inputs for getting a file from disk drive and two actions that have almost no code.
So if you have any idea, drop a line...
Magic points
Enabled magic points in the application at least for line and rectangle drawing.
Will continue with adding the magic points for solids like extrude and also improving the current code, task estimated to take half a day. The geometric solver will be improved also with coplanar detection, that would enable using plane type magic points - used for example at making extrusions with the same height.
Will also work at implementing a test plugin that receive info through pipes form the application.
The technical solution for the magic points was to implement a solver pipe which receives events from the mouse 3d pipe and passes the points through the solver (it also displays and hides magic points when something detected). The line and rectangle drawers receive the 3d points from the solver pipe.
Subscribe to:
Posts (Atom)