< Summary

Class:GenerateCone
Assembly:bamlab.micromissiles
File(s):/github/workspace/Assets/Scripts/Editor/GenerateCone.cs
Covered lines:0
Uncovered lines:100
Coverable lines:100
Total lines:144
Line coverage:0% (0 of 100)
Covered branches:0
Total branches:0
Covered methods:0
Total methods:9
Method coverage:0% (0 of 9)

Metrics

MethodBranch coverage Crap Score Cyclomatic complexity NPath complexity Sequence coverage
GenerateCone()0%2100%
CreateCone()0%6200%
GenerateConeObject(...)0%6200%
GetBasePoints(...)0%6200%
Trig(...)0%2100%
BuildConeVertices(...)0%20400%
ConstructCone(...)0%90900%
CreateConeMesh(...)0%12300%
CalculateCenter(...)0%6200%

File(s)

/github/workspace/Assets/Scripts/Editor/GenerateCone.cs

#LineLine coverage
 1using UnityEngine;
 2using UnityEditor;
 3using System;
 4using System.Collections.Generic;
 5
 6#if UNITY_EDITOR
 7public class GenerateCone : EditorWindow {
 08  private int sides = 16;
 09  private float baseRadius = 1f;
 010  private float height = 2f;
 11
 12  [MenuItem("GameObject/3D Object/Cone", false, 10)]
 013  static void CreateCone() {
 14    GameObject cone;
 015    GameObject selectedObject = Selection.activeGameObject;
 16
 017    if (selectedObject != null) {
 18      // Create as child of selected object
 019      cone = new GameObject("Cone");
 020      cone.transform.SetParent(selectedObject.transform, false);
 021    } else {
 22      // Create as new root object
 023      cone = new GameObject("Cone");
 024    }
 25
 026    cone.AddComponent<MeshFilter>();
 027    cone.AddComponent<MeshRenderer>();
 028    Undo.RegisterCreatedObjectUndo(cone, "Create Cone");
 29
 030    var window = ScriptableObject.CreateInstance<GenerateCone>();
 031    window.GenerateConeObject(cone);
 32
 033    Selection.activeGameObject = cone;
 034  }
 35
 036  void GenerateConeObject(GameObject cone) {
 037    Mesh mesh =
 38        CreateConeMesh("ConeMesh", sides, Vector3.zero, Quaternion.identity, baseRadius, height);
 39
 40    // Save the mesh as an asset
 041    string path = "Assets/Meshes";
 042    if (!AssetDatabase.IsValidFolder(path)) {
 043      AssetDatabase.CreateFolder("Assets", "Meshes");
 044    }
 045    string assetPath = AssetDatabase.GenerateUniqueAssetPath(path + "/ConeMesh.asset");
 046    AssetDatabase.CreateAsset(mesh, assetPath);
 047    AssetDatabase.SaveAssets();
 48
 49    // Assign the mesh to the MeshFilter
 050    cone.GetComponent<MeshFilter>().sharedMesh = mesh;
 051    cone.GetComponent<MeshRenderer>().material = new Material(Shader.Find("Standard"));
 052  }
 53
 054  Vector2[] GetBasePoints(int vertices, float radius) {
 55    const float TAU = 2f * Mathf.PI;
 056    var pts = new Vector2[vertices];
 057    var step = TAU / vertices;  // angular step between two vertices
 058    for (int i = 0; i < vertices; i++) {
 059      pts[i] = radius * Trig(i * step);  // convert polar coordinate to cartesian space
 060    }
 061    return pts;
 062  }
 63
 064  static Vector2 Trig(float rad) => new Vector2(Mathf.Cos(rad), Mathf.Sin(rad));
 65
 066  Vector3[] BuildConeVertices(Vector2[] baseVerts, float coneHeight) {
 067    if (baseVerts == null || baseVerts.Length < 3)
 068      throw new InvalidOperationException("Requires at least 3 base vertices.");
 069    var verts = new Vector3[baseVerts.Length + 1];
 070    verts[0] = new Vector3(0f, coneHeight, 0f);
 071    for (int i = 0; i < baseVerts.Length; i++) {
 072      verts[i + 1] = new Vector3(baseVerts[i].x, 0f, baseVerts[i].y);
 073    }
 074    return verts;
 075  }
 76
 077  void ConstructCone(Vector3[] coneVerts, List<Vector3> finalVerts, List<int> triangles) {
 078    if (coneVerts == null || coneVerts.Length < 4)
 079      throw new InvalidOperationException("Requires at least 4 vertices.");
 080    if (finalVerts == null || triangles == null)
 081      throw new ArgumentNullException();
 82
 083    finalVerts.Clear();
 084    triangles.Clear();
 85
 086    var rimVertices = coneVerts.Length - 1;
 87
 88    // Side faces
 089    for (int i = 1; i <= rimVertices; i++) {
 090      int a = i, b = i < rimVertices ? i + 1 : 1;
 091      AddTriangle(coneVerts[0], coneVerts[b], coneVerts[a]);
 092    }
 93
 94    // Base face
 095    for (int i = 1; i < rimVertices - 1; i++) {
 096      AddTriangle(coneVerts[1], coneVerts[i + 1], coneVerts[i + 2]);
 097    }
 98
 099    void AddTriangle(Vector3 t1, Vector3 t2, Vector3 t3) {
 0100      finalVerts.Add(t1);
 0101      finalVerts.Add(t2);
 0102      finalVerts.Add(t3);
 0103      triangles.Add(finalVerts.Count - 3);
 0104      triangles.Add(finalVerts.Count - 2);
 0105      triangles.Add(finalVerts.Count - 1);
 0106    }
 0107  }
 108  Mesh CreateConeMesh(string name, int sides, Vector3 apex, Quaternion rotation, float baseRadius,
 0109                      float height) {
 0110    var baseVerts = GetBasePoints(sides, baseRadius);
 0111    var coneVerts = BuildConeVertices(baseVerts, height);
 112
 0113    var verts = new List<Vector3>();
 0114    var tris = new List<int>();
 0115    ConstructCone(coneVerts, verts, tris);
 116
 0117    for (int i = 0; i < verts.Count; i++) {
 0118      verts[i] = rotation * (verts[i] - coneVerts[0]);
 0119    }
 120
 121    // Recenter the cone
 0122    Vector3 center = CalculateCenter(verts);
 0123    for (int i = 0; i < verts.Count; i++) {
 0124      verts[i] = verts[i] - center + apex;
 0125    }
 126
 0127    Mesh mesh = new Mesh();
 0128    mesh.name = name;
 0129    mesh.SetVertices(verts);
 0130    mesh.SetTriangles(tris.ToArray(), 0);
 0131    mesh.RecalculateNormals();
 132
 0133    return mesh;
 0134  }
 135
 0136  Vector3 CalculateCenter(List<Vector3> vertices) {
 0137    Vector3 sum = Vector3.zero;
 0138    foreach (Vector3 vert in vertices) {
 0139      sum += vert;
 0140    }
 0141    return sum / vertices.Count;
 0142  }
 143}
 144#endif