a BUG!! in DrawBezier() function [SOLVED]
-
On 11/01/2015 at 15:18, xxxxxxxx wrote:
User Information:
Cinema 4D Version: 13+
Platform: Windows ;
Language(s) : C++ ;---------
I was testing DrawBezier() function in GeUserArea inside GeDialogue, there is a typical bug ...#define LEN 2 // Two Bezier curves Float p[LEN*3*2]; // Allocates an array of 6 points for(int i = 1; i <= LEN*3*2; i += 2) { p[i-1] = i * 10 + 100; p[i] = i * 10 + 10; } DrawSetPen(Vector(0.8, 0.2, 0.3)); DrawBezier(100, 10, p, LEN, false , false); for(int i = 1; i <= LEN*3*2; i += 2) { p[i-1] = i * 10 + 40; p[i] = i * 10 + 10; } DrawSetPen(Vector(0.8, 0.2, 0.3)); DrawBezier(40, 10, p, LEN, true , false);
-
On 11/01/2015 at 15:33, xxxxxxxx wrote:
What is the 'typical bug' (as I don't that much Bezier curve math to see it offhand)?
-
On 11/01/2015 at 16:43, xxxxxxxx wrote:
if I make only 1 bezier curve, it draws fine "a straight line because all the 4 points are on 1 line" , if I make 2 bezier curves or more, it draws in a very weird way!! "although all points are on the same line" , check the code above, test it with LEN = 1 to see how it works, LEN = 2 or more = fail
-
On 11/01/2015 at 17:13, xxxxxxxx wrote:
DrawBezier() is only available in R14+ (not available in R13 from the docs, anywho). It may be that reusing the p[] array is the problem. Maybe an array of 12 points (2*6) would avoid the anomaly.
Note: Due to improve speed performance, the elements of p will be modified and might be invalid and all values must be set again if DrawBezier() will be called again with the same array.
This might indicate that for a concatenated set of Bezier splines, you need to store all of them uniquely until all drawn since there are modifications to the existing elements of the array p. While this may be stating for subsequent usages, it may also apply to local usages of that array. So, for two segments, you probably want to have a contiguous array over both spline segments and draw it out once with those two segments rather than doing it in two separate calls.
Id est:
#define LEN 2 // Two Bezier curves Float p[LEN*3*2]; // Allocates an array of 6 points for(int i = 0; i < 3*2; i += 2) { p[i] = i * 10 + 100; p[i+1] = i * 10 + 10; } DrawSetPen(Vector(0.8, 0.2, 0.3)); DrawBezier(100, 10, p, 1, false , false); for(int i = 3*2; i < LEN*3*2; i += 2) { p[i] = i * 10 + 40; p[i+1] = i * 10 + 10; } DrawSetPen(Vector(0.8, 0.2, 0.3)); DrawBezier(40, 10, p, 1, true , false);
or
#define LEN 2 // Two Bezier curves Float p[LEN*3*2]; // Allocates an array of 6 points for(int i = 0; i < 3*2; i += 2) { p[i] = i * 10 + 100; p[i+1] = i * 10 + 10; } for(int i = 3*2; i < LEN*3*2; i += 2) { p[i] = i * 10 + 40; p[i+1] = i * 10 + 10; } DrawSetPen(Vector(0.8, 0.2, 0.3)); DrawBezier(40, 10, p, 2, true , false);
But the two segments start at the same coordinate and you would need to add an offset tp the Bezier points to achieve the same results.
As always with C4D SDK, trial-and-error, test and see are the only way to find answers.
ETA: As with all C4D splines, closed or open is over the scope of the entire spline and its inclusive segments. You cannot have multiply-segmented splines that are both opened and closed at segments. It is a spline-level condition, not one that can vary at the segment level.
-
On 12/01/2015 at 01:57, xxxxxxxx wrote:
hey Robert, thanks for clarification about R13 , I'm using R15 SDK and thought it was included in R13
about the 2 codes that you posted, they are not the same, and it never draws as expected.
I wanted concatenated Bezier Curves to be connected in 1 draw so I can fill them and Draw a cool looking node "with round corners" instead of the rectangular node.you know any good method to draw any custom shape "easily" which is supported by R13?
and really your replies here and in the other thread are pretty helpful, thanks again
-
On 13/01/2015 at 14:36, xxxxxxxx wrote:
Hi MohamedSakr,
I looked over the implementation of DrawBezier() in the R16 code base, and didn't find any issues, meaning it should work as expected when given the proper data. However, your code had an error that Kyroyume's code fixed but he didn't mention it: your for loops went one past the end of the p array with "i <= LEN*3*2". He corrected it with variations of ""i < LEN*3*2". C++ is very unforgiving with regards to such errors: it won't tell you it's wrong, the compiler doesn't even check, yet it'll malfunction, one way or another. The most obvious report is to hear about getting random results, as when it goes over the limit, there's no way of knowing what memory you're reading. Otherwise, it may easily crash, as the values might not be valid, or you may be going out of bounds in terms of memory space, which will likely cause a crash.
Unfortunately, for your direct question about R13, we only support R16. Plus, I'm not sure how to answer an open ended question such as "a good method to draw any custom shape "easily" ...". The most 'easy' in terms of control? That would be up to you to create a blank bitmap and draw into it yourself, with your own low level drawing calls.
Joey Gaspe
SDK Support Engineer -
On 14/01/2015 at 11:24, xxxxxxxx wrote:
Hi Joey,
did you test the code? the for loop is correct
it starts with "1" which is odd, and i+=2 , so the end is odd, that's why it won't crash because it will never get out of bound!!#define LEN 2 // Two Bezier curves Float p[LEN*3*2]; // Allocates an array of 6 points for(int i = 1; i <= LEN*3*2; i += 2) { p[i-1] = i * 10 + 100; p[i] = i * 10 + 10; }
edit:
test it with R15 if possible, as this is the version that I'm testing on.
+ thanks for the suggestion for an empty Bitmap filling "similar to ASync SDK example which is a very good idea"I tested Robert code with R15 also, and guess what? it didn't work as expected!! , this is a bug in R15 SDK that needs a confirmation, it may be fixed in R16 SDK, any way I will use the old way of "rectangular" nodes which is sufficient for now "in a latter luxury stage I will draw my own Bitmaps"
-
On 14/01/2015 at 11:45, xxxxxxxx wrote:
Hi MohamedSakr,
Sorry, I must have read the code too fast. I checked on paper, your loop definitely works, even if not of the usual 'zero to less than the size of the array' range.
Still, the call to DrawBezier() should still work, I don't know why you're having trouble with it.
Joey Gaspe
SDK Support Engineer -
On 14/01/2015 at 11:50, xxxxxxxx wrote:
Hi Joey,
I just edited the post and found your reply after editing , here is what I wrote in edit:
test it with R15 if possible, as this is the version that I'm testing on.
+ thanks for the suggestion for an empty Bitmap filling "similar to ASync SDK example which is a very good idea"I tested Robert code with R15 also, and guess what? it didn't work as expected!! , this is a bug in R15 SDK that needs a confirmation, it may be fixed in R16 SDK, any way I will use the old way of "rectangular" nodes which is sufficient for now "in a latter luxury stage I will draw my own Bitmaps"
-
On 16/01/2015 at 12:55, xxxxxxxx wrote:
Hi MohamedSakr,
I dived more deeply into this problem, since I felt there may be something going on. Here's what I found:
With your code:
- When I set LEN = 1, I get two parallel lines that don't change when I resize the dialog.
- When I set LEN = 2, I get curvy lines that somewhat resemble your snapshot, and they change form when I resize the dialog.
With kuroyume's code:
The drawings as you described.
- I can confirm that the six values get modified after returning from DrawBezier() in all cases, whether it's C4D drawing bezier curves, or any of the examples you provide, or my own code.
You must therefore use an array of size 6, and reset it for each DrawBezier() call, if you want results that match the curve point numbers you provide. When you look at the documentation, you see DRAWBEZIER_* values being used to set the array points. This is how I see it used in C4D's own code when drawing the rounded edges of the xpresso node boxes. The boxes I'm referring to are the ones you see in the user area that can be connected together that are created by right-clicking in that area and selecting one under 'New Node'. As you can observe, the rounded edges are always drawn correctly.
I don't know why the values are modified, as the stack goes very deep with recursive calls in this area, and it wouldn't change the fact of what you have to do (ie reset the array before each call). It may be related to the fact that when I stretch the window left-right, the drawings scale to its size, but when I stretch it up-down, the drawings stay the same size.
I hope that helps!
Joey Gaspe
SDK Support Engineer -
On 16/01/2015 at 15:49, xxxxxxxx wrote:
Hi Joey,
the documentation says "array of multiplier of 6 * LEN" , and this is what I did, I wanted to use multiple beziers for 1 reason "closed + fill".
anyway I guess I will rely on my own drawings , I have created my own bezier function "for R13" , using multiple linear calls, and for the node itself I will draw it using Bitmap, after all I find Cinema 4D drawing classes are very fast/easy to use , although sometimes they give unexpected results, but they are still decent.
this discussion gave me good 2 points:
1- beziers are not supported by R13 "regardless if they are bugged in R15 or not, I won't use them"
2- drawing with filled custom Bitmaps is a good option.thanks for the help Joey, Robert.
-
On 16/01/2015 at 16:10, xxxxxxxx wrote:
Hi MohamedSakr,
Glad to hear my info helped you out, and that you found a solution! I'll set this topic as solved.
Joey Gaspe
SDK Support Engineer