Notifications
Clear all

[Closed] get Index of reversed Spline

Is there any maxscript way of getting the indexes of ‘reversed’ splines (those splines indexes that form a hole after we convert splineshape to mesh)?
These indexes are in hie.Reverse IBitArray, but I have no idea how to get them easily. max 2014


(
fn shapeReversedIndexes shp = (

    g = (dotnetclass "autodesk.max.globalinterface").instance
    inode = g.COREInterface14.GetINodeByHandle shp.inode.handle asdotnetobject:true
    iobj  = (inode.EvalWorldState g.COREInterface.Time true asdotnetobject:true).Obj

    cw = #{}
    for i=0 to iobj.Shape_.SplineCount_-1 do cw[i+1] = (iobj.Shape_.GetSpline(i)).IsClockWise
    cw        
)
        
fn shapeHasHoles shp = (

    g = (dotnetclass "autodesk.max.globalinterface").instance
    inode = g.COREInterface14.GetINodeByHandle shp.inode.handle asdotnetobject:true
    iobj  = (inode.EvalWorldState g.COREInterface.Time true asdotnetobject:true).Obj

    iHierarchy =  g.ShapeHierarchy.Create  asdotnetobject:true
    hie = iobj.OrganizeCurves g.COREInterface.Time iHierarchy  asdotnetobject:true

    not hie.Reverse.IsEmpty

)


delete objects
    
donut radius1:33 radius2:66
rectangle()
circle()

n = converttosplineshape (ngon radius:66)
addandweld n (converttosplineshape (ngon radius:33)) -1
reverse n 2
updateshape n    

max create mode    
for s in shapes do (
    
    converttosplineshape s
    gc()
    t1=timestamp()
    hf = heapfree
    
    res = shapeHasHoles s
    
    format "Time: %sec. Mem: % Shape:% Result: %
" ((timestamp()-t1)/1000 as float) (hf-heapfree) s.name res
    format "Shape:% Reversed:%
-------------
" s.name (shapeReversedIndexes s)
    
)

    
)

14 Replies

i’ve extended this example with GetBits method. it lets you convert IBitArray to int array (int[])


global MaxSDKAssembly
fn CreateMaxSDKAssembly forceRecompile:on =
(
   if forceRecompile or not iskindof ::MaxSDKAssembly dotnetobject or (::MaxSDKAssembly.GetType()).name != "Assembly" do
   (
source = ""
source += "using System;
"
source += "using System.Collections.Generic;
"
source += "using Autodesk.Max;
"
source += "public class MaxSDK
"
source += "{
"
source += "   public Object GetGlobal()
"
source += "   {
"
source += "      return Autodesk.Max.GlobalInterface.Instance;
"
source += "   }
"
source += "   public IPoint3 GetPoint(float x, float y, float z)
"
source += "   {
"
source += "      IPoint3 pt = Autodesk.Max.GlobalInterface.Instance.Point3.Create(x, y, z);
"
source += "      return pt;
"
source += "   }
"
source += "   public IBitArray MakeBits(int size)
"
source += "   {
"
source += "      return Autodesk.Max.GlobalInterface.Instance.BitArray.Create(size);
"
source += "   }
"
source += "   public int GetBit(IBitArray bits, int index)
"
source += "   {
"
source += "      return bits[index];
"
source += "   }
"
source += "   public int[] GetBits(IBitArray bits)
"
source += "   {
"
source += "      List<int> _bits = new List<int>();
"
source += "      for (int index = 0; index < bits.Size; index++)
"
source += "      {;
"
source += "         if (bits[index] == 1) _bits.Add(index+1);
"
source += "      };
"
source += "      return _bits.ToArray();
"
source += "   }
"
source += "   public Object ORBits(IBitArray a, IBitArray b)
"
source += "   {
"
source += "      return a.BitwiseNot.BitwiseAnd(b.BitwiseNot).BitwiseNot;
"
source += "   }
"
source += "   public Object ORBits2(IBitArray a, IBitArray b)
"
source += "   {
"
source += "      return a.BitwiseXor(b).BitwiseXor(a.BitwiseAnd(b));
"
source += "   }
"
source += "}
"
      csharpProvider = dotnetobject "Microsoft.CSharp.CSharpCodeProvider"
      compilerParams = dotnetobject "System.CodeDom.Compiler.CompilerParameters"
      compilerParams.ReferencedAssemblies.AddRange #("System.dll", getdir #maxroot + @"Autodesk.Max.dll")
      compilerParams.GenerateInMemory = true
      compilerResults = csharpProvider.CompileAssemblyFromSource compilerParams #(source)
      
      if (compilerResults.Errors.Count > 0 ) then
      (
         errs = stringstream ""
         for i = 0 to (compilerResults.Errors.Count-1) do
         (
            err = compilerResults.Errors.Item[i]
            format "Error:% Line:% Column:% %
" err.ErrorNumber err.Line err.Column err.ErrorText to:errs 
         )
         MessageBox (errs as string) title: "Errors encountered while compiling C# code"
         format "%
" errs
         undefined
      )
      else
      (
         MaxSDKAssembly = compilerResults.CompiledAssembly
         MaxSDKAssembly.CreateInstance "MaxSDK"
      )
   )
)
MaxSDK = CreateMaxSDKAssembly()
/*
gi = MaxSDK.GetGlobal()
b = gi.BitArray.Create 10
b.get_Item(0)
b.Set 0
b.get_Item(0)
MaxSDK.GetBit b 0
MaxSDK.GetBits b
*/

Thx, Denis. Maybe there’s a way I can cast IBitArray to int[] some other way?
My max2014 throws this when compiling it: “Cannot apply indexing with [] to an expression of type ‘Autodesk.Max.IBitArray’”

I remember Andres was struggling to make it work:


    public static class IBitArrayExtensions
    {
        private const int NSHIFT = 6;
        private const int CHAR_BIT = 8;
        private const int kMAX_LOCALBITS = CHAR_BIT * sizeof( ulong );

        private const int BITS_PER_DWORD_PTR = (CHAR_BIT * sizeof( ulong ));
        private const int BITS_PER_DWORD_PTR_MASK = BITS_PER_DWORD_PTR - 1;

        public static unsafe bool GetBit( this IBitArray bitArray, int index )
        {
            int numBits = bitArray.Size;

            //Pointer to the start of either DWORD_PTR* bits or DWORD_PTR localBits
            //DWORD_PTR is of type ulong
            void* nativePtr = bitArray.Handle.ToPointer();

            //Determines whether we use bits or localBits
            bool useLocal = numBits <= kMAX_LOCALBITS;

            if ( useLocal )
            {
                ulong localBits = ((ulong*)nativePtr)[0];
                ulong bitMask = (index < kMAX_LOCALBITS) ? (((ulong)1) << index) : 0;
                return ((localBits & bitMask) != 0) ? true : false;
            }
            else
            {
                ulong* bits = ((ulong**)nativePtr)[0];
                int bitIndex = index >> NSHIFT;
                var bitMaskParameter = index & BITS_PER_DWORD_PTR_MASK;
                ulong bitMask = (bitMaskParameter < kMAX_LOCALBITS) ? (((ulong)1) << bitMaskParameter) : 0;
                return ((bits[bitIndex] & bitMask) != 0) ? true : false;
            }
        }
    }

i don’t have max 2014 now…
how does things below work for you?


gi = MaxSDK.GetGlobal()
b = gi.BitArray.Create 10
b.get_Item(0)
b.Set 0
b.get_Item(0) 

There’s no Get method in 2014, unfortunately.


a = gi.BitArray.Create 1
a.set 0
b = gi.BitArray.Create 10
b.set 0
b.set 2
b.set 4
b.set 6
bits = #{}
for k=1 to b.Size do 
(
   if not (b.BitwiseAnd a).IsEmpty do append bits k
   b.Shift 0 1 0
)
bits

it has to work in 2014, and it should be easy to make c# version

1 Reply
(@polytools3d)
Joined: 11 months ago

Posts: 0

Mmm. There might be a bug in the .Net wrapper, because this leads to very weird results. (Same results in Max 2014 to 2018)


(
    gi = (dotnetclass "autodesk.max.globalinterface").instance

    a = gi.BitArray.Create 1
    a.set 0
    
    b = gi.BitArray.Create 200
    for j in #{17, 27, 31, 43, 45, 60, 81, 87, 118, 134, 163} do b.Set j

    bits = #{}
    
    for k=1 to b.Size do
    (
       if not (b.BitwiseAnd a).IsEmpty do append bits k
       b.Shift 0 1 0
    )
    
    bits
)

In Max 2016+ where you can access the IBitarray by index, you can verify that this works, so I suspect it is the Shift() method what is not working correctly:


(
    gi = (dotnetclass "autodesk.max.globalinterface").instance
    
    b = gi.BitArray.Create 200
    for j in #{17, 27, 31, 43, 45, 60, 81, 87, 118, 134, 163} do b.Set j

    bits = #{}
    
    for k=1 to b.Size where (b.get_item k) == 1 do bits[k] = true
    
    bits
)

And it does. It modifies original bitarray, but I know how to deal with that.
Thanks again


-- here was not working solution

Wow!

Here is a different function, which additionally is exponentially faster.


(
    fn IBitarrayToBitarray IBitArray =
    (
        result = #{}
        
        if not IBitArray.isEmpty do
        (
            gi = (dotNetClass "Autodesk.Max.GlobalInterface").instance
            
            tmp = gi.BitArray.Create IBitArray.Size

            for j = 0 to IBitArray.Size-1 do
            (
                tmp.ClearAll()
                tmp.Set j
                if (IBitArray.BitwiseAnd tmp).AnyBitSet do result[j+1] = true
            )
        )
        return result
    )
)

[quote=]for j = 1 to IBitArray.Size doIBitArray is zero based so it should be like this I think.

for j = 0 to IBitArray.Size-1 do 
Page 1 / 2