The CRef < operator does not behave correctly with assigned materials and wouldneed to be fixed. The lexicographic comparison is ok for regular objects but not for assigned materials which is a special case.
I'm pretty sure your test case would work if materials were added with AddMaterial. -mab From: [email protected] [mailto:[email protected]] On Behalf Of Nicolas Burtnyk Sent: Tuesday, May 08, 2012 1:05 PM To: [email protected] Subject: Re: Why is Material::operator& private? Hi Bosheng, Thanks for your reply. As I mentioned to ADN support after they responded this morning saying the behavior is by design, at the very least the documentation should be updated to remove the statement that CRef::operator< is suitable for STL sorted containers like std::map, because it's not. Also, I don't think your proposed solution is suitable for sorted STL containers which require strict weak ordering (like std::map or std::set). I assume you mean that I could do something like this: struct CRef_less { inline bool operator() (const CRef& lhs, const CRef& rhs) const { return lhs != rhs && lhs<rhs; } }; A strict weak ordering has the following properties: Irreflexivity: for all x, x < x is false Transitivity: for all x, y and z, if x < y and y < z then x < z The above predicate CRef_less is indeed Irreflexive but is not Transitive! Suppose you have 3 CRefs A, B & C with the following names: "A.Material", "B.AnotherMaterial" and "C.Material". A and C refer to the same material assigned to 2 different objects. The CRefs compare equal with ==, but obviously A compares lesser than C lexicographically. As a result: CRef_less()(A, B) returns true CRef_less()(B, C) returns true CRef_less()(A, C) returns false If you were for example to do something like this: std::set<CRef, CRef_less> mySetOfCRefs; mySetOfCRefs.insert(A); mySetOfCRefs.insert(B); mySetOfCRefs.insert(C); you would sadly discover that the set would contain 3 elements instead of the expected 2 - not much of a set anymore, is it? I'll stick to using GetObjectID for sorted containers, though it can be worth adding a check for inequality if you expect lots of duplicates since it can early out and prevent constriction of 2 ProjectItems: struct CRef_less { inline bool operator() (const CRef& lhs, const CRef& rhs) const { return lhs != rhs && ProjectItem(lhs).GetObjectID() < ProjectItem(rhs).GetObjectID(); } } -Nicolas On Mon, May 7, 2012 at 9:38 PM, Bosheng An <[email protected]<mailto:[email protected]>> wrote: Hi Nicholas, My name is Bosheng and I am a developer from Softimage. Thank you for your statement here and your mention is true, but I think we designed these comparison logic purposely. We just defined our CRef ">" and "<" that way. I guess what you would like to do is twisting the predicate in your sort function a bit to: using "==" to check whether the two operands are the same object before invoking ">" or "<". Sorry for the inconvenience. Thanks and Regards, Bosheng. From: [email protected]<mailto:[email protected]> [mailto:[email protected]<mailto:[email protected]>] On Behalf Of Nicolas Burtnyk Sent: Saturday, May 05, 2012 7:31 AM To: [email protected]<mailto:[email protected]> Subject: Re: Why is Material::operator& private? Well I'm glad this list exists! It's great for bouncing ideas around and the fact that the Soft devs are actually active here is fantastic! I hope I can start to contribute more and be helpful to others. On Fri, May 4, 2012 at 3:59 PM, Raffaele Fragapane <[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>>> wrote: I don't know who you are Nicolas, but I'm suddenly glad we have you around on the list and using Soft :) On May 5, 2012 2:21 AM, "Nicolas Burtnyk" <[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>>> wrote: Unfortunately, that doesn't work. CRef::operator< performs a lexicographical comparison using CRef::GetAsText(). In my scene when I have the same material assigned to multiple objects, the CRefs I get back from X3DObject::GetMaterials() give me different results from GetAsText even though they compare equal (and they are indeed the same material). Example: A bunch of objects with "Scene_Material" assigned, and 1 object (torus) with "Material" assigned. This is the result of calling GetAsText on all the materials I get from calling GetMaterials on all the meshes in the scene. //all materials (unsorted) Model1.sphere.Scene_Material Model.cube.Scene_Material Model.cylinder.Scene_Material Model_Instance.torus.Material cone.Scene_Material Material disc.Scene_Material Material These materials are in a std::vector<CRef> called "materials". I then want to remove duplicates, so I call: std::sort( materials.begin(), materials.end(), CRef_Pred::less() ); materials.erase( std::unique( materials.begin(), materials.end(), CRef_Pred::equal() ), materials.end() ); where the predicates here evaluate to CRef::operator< and CRef::operator==, respectively. In case you're not familiar with the stl algorithms, std::unique removes duplicates from a sorted range by moving them to the end of the container and returning the new end of the range with no duplicates. The important thing is that the range must be sorted for the algorithm to work correctly. Turns out that the lexicographical comparison is not appropriate for CRef sorting since 2 CRefs can be both equal and less than at the same time! CRef m1, m2; m1.Set(L"cone.Scene_Material Material") m2.Set(L"disc.Scene_Material Material") m1 == m2; //true! m1 < m2; //true! assert( (m1 == m2) != (m1 < m2) ); // <--- Wrong assumption! So, as a result, calling std::sort on my vector of CRefs doesn't correctly sort the vector: //all materials (sorted) Model.cube.Scene_Material Model.cylinder.Scene_Material Model1.sphere.Scene_Material Model_Instance.torus.Material <-- Oops! cone.Scene_Material disc.Scene_Material And therefore my removal of duplicates doesn't work correctly: //all materials (unique) Model.cube.Scene_Material <-- ! Model_Instance.torus.Material cone.Scene_Material <-- ! So CRef::operator< is not suitable for sorting. On a side note, that means it's also not really suitable for use in a map (the line in the docs "This is useful for sorting operations with stl maps." is not correct.). -Nicolas On Fri, May 4, 2012 at 4:27 AM, Marc-Andre Belzile <[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>>> wrote: Do you really need to instantiate ProjectItem objects ? Try using CRef::operator < in your predicate instead. -mab ________________________________ From: [email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>> [[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>>] on behalf of Steven Caron [[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>>] Sent: Thursday, May 03, 2012 8:46 PM To: [email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>> Subject: Re: Why is Material::operator& private? in a rendering context speed is paramount, keep up the good fight! and the pressure on the autodesk to make the improvements you need. On Thu, May 3, 2012 at 5:41 PM, Nicolas Burtnyk <[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>><mailto:[email protected]<mailto:[email protected]><mailto:[email protected]<mailto:[email protected]>>>> wrote: the on-the-fly construction of 2 ProjectItems to do the comparison is a lot slower than if I had those ProjectItems (or Materials or whatever) already. Slow is a relative term so let me be more specific - on my machine, constructing 100 Materials from 100 CRefs and calling GetObjectID takes about 0.16ms whereas simply calling GetObjectID on 100 Materials take only about 0.001ms. Probably not a big deal :)
<<attachment: winmail.dat>>

