[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)
)
)
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)
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
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
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