Not a member of Pastebin yet?
Sign Up,
it unlocks many cool features!
- public static class ExtentCalculator
- {
- public static void Calculate(CModel model)
- {
- //--------------------------------------------------------------
- // null extents in advance, to start fresh
- //--------------------------------------------------------------
- model.Extent = new CExtent();
- foreach (var sequence in model.Sequences) sequence.Extent = new CExtent();
- foreach (var geoset in model.Geosets) { geoset.Extent = new CExtent(); geoset.Extents.Clear(); }
- //--------------------------------------------------------------
- if (model.Geosets.Count == 0) { return; } // nothing to calculate :(
- //--------------------------------------------------------------
- //1. calcualte basic geoset extent
- foreach (var geoset in model.Geosets) geoset.Extent = GetExtent_fromVectors(geoset.Vertices.Select(x=>x.Position).ToList());
- //2. calculate geoset sequence extents
- foreach (var geoset in model.Geosets) CalculateGeosetSequenceExtents(geoset, model);
- // no sequences = no geoset sequence extents, sequence extetns and model extents :(
- if (model.Sequences.Count == 0) { return; }
- //3. sum up sequence extents
- for (var i = 0; i < model.Sequences.Count; i++)
- {
- var sequence = model.Sequences[i];
- // the <sequence> extent of each geoset
- List<CExtent> extents = model.Geosets.Select(x => x.Extents[i].Extent).ToList();
- // inflate the geoset to the maximum from all in the list
- sequence.Extent = GetMaxExtent(extents);
- }
- //4. sum up sequence extents and assign to <model> extent
- model.Extent = GetMaxExtent(model.Sequences.Select(x=>x.Extent).ToList());
- }
- private static void CalculateGeosetSequenceExtents(CGeoset whichGeoset, CModel whichModel)
- {
- whichGeoset.Extents.Clear(); // clear before addign new
- foreach (var sequence in whichModel.Sequences)
- {
- if (ExtentVisibleInSequence(whichGeoset, sequence, whichModel) == false)
- {
- whichGeoset.Extents.Add(new CGeosetExtent(whichModel) { Extent = new CExtent() });
- continue;
- }
- List<CVector3> ModifiedPositions = new List<CVector3>();
- // get sequence extednt
- int from = sequence.IntervalStart;
- int to = sequence.IntervalEnd;
- foreach (var vertex in whichGeoset.Vertices)
- {
- HashSet<INode> VisitedNodes = new HashSet<INode>(); // this is for preventing deep-nessted circular faulty node relationships in order to avoid infinite loop
- List<CVector3> All_Reached_Vextex_Posiitons = new List<CVector3>();
- CVector3 InitialPosition = new CVector3(vertex.Position);
- CVector3 FinalPosition = new CVector3( vertex.Position);
- var group = vertex.Group.Object;
- if (group == null) { ModifiedPositions.Add(new CVector3()); continue; }
- foreach (var gnode in group.Nodes)
- {
- var Loopednode = gnode.Node.Node;
- if (Loopednode == null) continue;
- // add a new position for each keyframe that changes it!
- FinalPosition = CalculateChange(InitialPosition, Loopednode,from, to);
- // no parent?
- if (Loopednode.Parent.Node == null) continue;
- // prevent infinite loop (self-referencing):
- if (Loopednode.Parent.Node == Loopednode) continue;
- // prevent infinite loop (mutual-referencing):
- if (Loopednode.Parent.Node == Loopednode.Parent.Node.Parent.Node) continue;
- FinalPosition = InheritChangeRecursive(Loopednode.Parent.Node, InitialPosition, from, to, VisitedNodes, ref All_Reached_Vextex_Posiitons);
- }
- ModifiedPositions.Add(GetBestOfVertex(InitialPosition, All_Reached_Vextex_Posiitons));
- }
- CExtent max = GetExtent_fromVectors(ModifiedPositions);
- whichGeoset.Extents.Add(new CGeosetExtent(whichModel) { Extent = max });
- }
- }
- private static bool ExtentVisibleInSequence(CGeoset whichGeoset, CSequence sequence, CModel model)
- {
- int from = sequence.IntervalStart;
- int to = sequence.IntervalEnd;
- CGeosetAnimation? any = model.GeosetAnimations.FirstOrDefault(x => x.Geoset.Object == whichGeoset);
- if (any != null)
- {
- if (any.Alpha.Static)
- {
- if (any.Alpha.GetValue() > 0) return true;
- else return false;
- }
- else
- {
- // Replace this line:
- // List<CAnimatorNode<float>> keyframes = any.Alpha.NodeList.Select(x=>x.Time >= from && x.Time <= to).ToList();
- // With this corrected line:
- List<CAnimatorNode<float>> keyframes = any.Alpha.NodeList
- .Where(x => x.Time >= from && x.Time <= to)
- .ToList();
- if (keyframes.Count > 0)
- {
- return keyframes.Any(x => x.Value > 0);
- }
- else
- {
- return true;
- }
- }
- }
- return true; // default
- }
- private static CVector3 GetBestOfVertex(CVector3 position, List<CVector3> all_Reached_Vextex_Posiitons)
- {
- CVector3 best = position;
- foreach (var v in all_Reached_Vextex_Posiitons)
- {
- // Check X axis
- if ((position.X >= 0 && v.X > best.X) || (position.X < 0 && v.X < best.X))
- best.X = v.X;
- // Check Y axis
- if ((position.Y >= 0 && v.Y > best.Y) || (position.Y < 0 && v.Y < best.Y))
- best.Y = v.Y;
- // Check Z axis
- if ((position.Z >= 0 && v.Z > best.Z) || (position.Z < 0 && v.Z < best.Z))
- best.Z = v.Z;
- }
- return best;
- }
- private static CVector3 InheritChangeRecursive(INode inheritFrom, CVector3 position, int from, int to, HashSet<INode> visitedNodes, ref List<CVector3> all_Reached_Vextex_Posiitons, float influence = 100f)
- {
- float InfluencePercent = 0; ;
- if (influence < 0) InfluencePercent = 0;
- else if (influence > 100) InfluencePercent = 1;
- else { InfluencePercent = influence / 100f; }
- // prevent deep circular infinite loop
- if (!visitedNodes.Add(inheritFrom)) return position;
- CVector3 workWith =new CVector3(position);
- // 1. scaling
- if (inheritFrom.DontInheritScaling == false)
- {
- foreach (var kf in inheritFrom.Scaling)
- {
- if (kf.Time < from || kf.Time > to) continue;
- workWith.X *= kf.Value.X / 100f;
- workWith.Y *= kf.Value.Y / 100f;
- workWith.Z *= kf.Value.Z / 100f;
- }
- }
- // 2. rotation
- if (inheritFrom.DontInheritRotation == false)
- {
- foreach (var kf in inheritFrom.Rotation)
- {
- if (kf.Time < from || kf.Time > to) continue;
- workWith = RotateAround(workWith, inheritFrom.PivotPoint, kf.Value);
- }
- }
- // 3. translation
- if (inheritFrom.DontInheritTranslation == false)
- {
- foreach (var kf in inheritFrom.Translation)
- {
- if (kf.Time < from || kf.Time > to) continue;
- workWith.X += kf.Value.X;
- workWith.Y += kf.Value.Y;
- workWith.Z += kf.Value.Z;
- }
- }
- // null parent?
- if (inheritFrom.Parent.Node == null) { all_Reached_Vextex_Posiitons.Add(new CVector3(workWith)); return workWith; }
- // prevent infinite loop (self-referencing):
- if (inheritFrom.Parent.Node == inheritFrom) { all_Reached_Vextex_Posiitons.Add(new CVector3(workWith)); return workWith; }
- // prevent infinite loop (mutual-referencing):
- if (inheritFrom.Parent.Node == inheritFrom.Parent.Node.Parent.Node) { all_Reached_Vextex_Posiitons.Add(new CVector3(workWith)); return workWith; }
- // check for more parents to inherit from
- if (inheritFrom.Parent.Node != null)
- {
- workWith = InheritChangeRecursive(inheritFrom.Parent.Node, workWith, from,to, visitedNodes, ref all_Reached_Vextex_Posiitons);
- }
- return workWith;
- }
- private static CVector3 CalculateChange(CVector3 position, INode node,int from, int to)
- {
- CVector3 initial = new CVector3(position);
- //1. scaling
- foreach (var kf in node.Scaling)
- {
- if (kf.Time < from || kf.Time > to) continue;
- initial.X *= kf.Value.X / 100f;
- initial.Y *= kf.Value.Y / 100f;
- initial.Z *= kf.Value.Z / 100f;
- }
- //2. rotation
- foreach (var kf in node.Rotation)
- {
- if (kf.Time < from || kf.Time > to) continue;
- initial = RotateAround(initial, node.PivotPoint, kf.Value);
- }
- // 3. translation
- foreach (var kf in node.Translation)
- {
- if (kf.Time < from || kf.Time > to) continue;
- initial.X += kf.Value.X;
- initial.Y += kf.Value.Y;
- initial.Z += kf.Value.Z;
- }
- return initial;
- }
- private static CVector3 RotateAround(CVector3 vertexPosition, CVector3 aroundPivotPoint, CVector4 quaternion)
- {
- // Translate the vertex so the pivot is at the origin
- float x = vertexPosition.X - aroundPivotPoint.X;
- float y = vertexPosition.Y - aroundPivotPoint.Y;
- float z = vertexPosition.Z - aroundPivotPoint.Z;
- // Quaternion components
- float qx = quaternion.X;
- float qy = quaternion.Y;
- float qz = quaternion.Z;
- float qw = quaternion.W;
- // Quaternion rotation formula: v' = q * v * q^-1
- // Compute intermediate products
- float ix = qw * x + qy * z - qz * y;
- float iy = qw * y + qz * x - qx * z;
- float iz = qw * z + qx * y - qy * x;
- float iw = -qx * x - qy * y - qz * z;
- // Compute rotated coordinates
- float rx = ix * qw + iw * -qx + iy * -qz - iz * -qy;
- float ry = iy * qw + iw * -qy + iz * -qx - ix * -qz;
- float rz = iz * qw + iw * -qz + ix * -qy - iy * -qx;
- // Translate back
- return new CVector3(rx + aroundPivotPoint.X, ry + aroundPivotPoint.Y, rz + aroundPivotPoint.Z);
- }
- private static CExtent GetExtent_fromVectors(List<CVector3> list)
- {
- if (list == null || list.Count == 0)
- return new CExtent(); // return empty extent if list is empty
- // Initialize min and max with the first point
- float minX = list[0].X;
- float minY = list[0].Y;
- float minZ = list[0].Z;
- float maxX = list[0].X;
- float maxY = list[0].Y;
- float maxZ = list[0].Z;
- foreach (CVector3 point in list)
- {
- if (point.X < minX) minX = point.X;
- if (point.Y < minY) minY = point.Y;
- if (point.Z < minZ) minZ = point.Z;
- if (point.X > maxX) maxX = point.X;
- if (point.Y > maxY) maxY = point.Y;
- if (point.Z > maxZ) maxZ = point.Z;
- }
- CExtent e = new CExtent
- {
- Min = new CVector3(minX, minY, minZ),
- Max = new CVector3(maxX, maxY, maxZ)
- };
- e.Radius = SetRadiusOfExtent(e);
- return e;
- }
- private static CExtent GetMaxExtent(List<CExtent> extents)
- {
- if (extents == null || extents.Count == 0)
- return new CExtent(); // return empty extent if list is empty
- // Initialize min and max with the first extent
- float minX = extents[0].Min.X;
- float minY = extents[0].Min.Y;
- float minZ = extents[0].Min.Z;
- float maxX = extents[0].Max.X;
- float maxY = extents[0].Max.Y;
- float maxZ = extents[0].Max.Z;
- foreach (CExtent extent in extents)
- {
- if (extent.Min.X < minX) minX = extent.Min.X;
- if (extent.Min.Y < minY) minY = extent.Min.Y;
- if (extent.Min.Z < minZ) minZ = extent.Min.Z;
- if (extent.Max.X > maxX) maxX = extent.Max.X;
- if (extent.Max.Y > maxY) maxY = extent.Max.Y;
- if (extent.Max.Z > maxZ) maxZ = extent.Max.Z;
- }
- CExtent result = new CExtent
- {
- Min = new CVector3(minX, minY, minZ),
- Max = new CVector3(maxX, maxY, maxZ)
- };
- result.Radius = SetRadiusOfExtent(result);
- return result;
- }
- private static float SetRadiusOfExtent(CExtent e)
- {
- var center = new CVector3(
- (e.Min.X + e.Max.X) / 2f,
- (e.Min.Y + e.Max.Y) / 2f,
- (e.Min.Z + e.Max.Z) / 2f
- );
- float dx = e.Max.X - center.X;
- float dy = e.Max.Y - center.Y;
- float dz = e.Max.Z - center.Z;
- return (float)Math.Sqrt(dx * dx + dy * dy + dz * dz);
- }
- }
Advertisement
Add Comment
Please, Sign In to add comment