{"id":16960989,"url":"https://github.com/cubbossa/splinelib","last_synced_at":"2025-06-24T21:03:27.740Z","repository":{"id":122849145,"uuid":"402493090","full_name":"CubBossa/SplineLib","owner":"CubBossa","description":"A library for particle path and shape creation in Minecraft","archived":false,"fork":false,"pushed_at":"2022-09-24T09:25:59.000Z","size":199,"stargazers_count":5,"open_issues_count":0,"forks_count":0,"subscribers_count":1,"default_branch":"master","last_synced_at":"2025-04-11T22:11:30.617Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":"Java","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/CubBossa.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null}},"created_at":"2021-09-02T16:40:09.000Z","updated_at":"2023-08-11T17:44:02.000Z","dependencies_parsed_at":null,"dependency_job_id":"77b78bea-bce7-4b86-9df9-b06654484e5e","html_url":"https://github.com/CubBossa/SplineLib","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/CubBossa/SplineLib","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CubBossa%2FSplineLib","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CubBossa%2FSplineLib/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CubBossa%2FSplineLib/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CubBossa%2FSplineLib/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/CubBossa","download_url":"https://codeload.github.com/CubBossa/SplineLib/tar.gz/refs/heads/master","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/CubBossa%2FSplineLib/sbom","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":261756454,"owners_count":23205143,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-10-13T22:50:43.587Z","updated_at":"2025-06-24T21:03:27.685Z","avatar_url":"https://github.com/CubBossa.png","language":"Java","funding_links":[],"categories":[],"sub_categories":[],"readme":"# SplineLib\n\nA library for particle path and shape creation. Work on this library is still in progress! Use classes with caution\nuntil release 1.0\n\nTODO erklärendes Bild\n\n## Contents\n- [Usage](#usage)\n  - [Splines and Terminology](#splines-and-terminology)\n  - [Shapes](#shapes)\n  - [Registering the Library](#registering-the-library)\n  - [Builder](#builder)\n    - [Instantiating](#instantiating)\n    - [Rounding Interpolator](#rounding-interpolator)\n    - [Spacing Interpolator](#spacing-interpolators)\n    - [Closing Splines](#closing-the-path)\n    - [Filters and Processors](#filters-and-processors)\n  - [Creating Phases](#creating-phases)\n- [Examples](#examples)\n\n## Usage\n\n### Splines and Terminology\n\nThe term \"spline\" is used to describe smoothing and interpolating functions. In this library, \"spline\" explicitly means\ncurves that are defined by any amount of control points. So all those examples are splines:\n\n(white: curve points, red: bezier vectors, green: control points) \n\n\u003cimg src=\"images/example_circle.png\" width=\"24%\"\u003e \u003cimg src=\"images/example_star.png\" width=\"24%\"\u003e \u003cimg src=\"images/example_spline.png\" width=\"24%\"\u003e \u003cimg src=\"images/example_spline2.png\" width=\"24%\"\u003e\n\n\nIn context of this library splines are simply lists of BezierVectors. A BezierVector extends the internal Vector class\nand contains two further Vectors: leftControlPoint and rightControlPoint. In order to define Bézier curves controlpoints\nare obligatory.\n\n### Shapes\n\nShapes are objects that are defined by a spline. They accept parameters like a pose and a radius. The Pose class is a\ncombination of a position vector, a direction vector and an up vector. It defines the position and facing direction in\n3D space. To get a spline from a shape you can call getSpline() from the Shape interface.\n\nPredefined Shapes can be found in the Shapes class:\n\n```java\npublic class Example {\n\tShapes.rectangle(pose,sizeX,sizeY);\n\tShapes.circle(pose,radius);\n\tShapes.star(pose,spikes,smoothing,innerRadius,outerRadius);\n}\n```\n\n### Registering the Library\n\nThis library is meant to help with path creation in 3D space. This can for example be useful in Minecraft development.\nBukkits Vector/Location classes are necessary to spawn particles on a curve. The SplineLib class itself is abstract. You\nwill need to implement methods for converting into an internal vector and back to your required vector class. Here is an\nexample of doing this for the Minecraft Bukkit Vector class.\n\n```java\npublic class Example {\n  private final SplineLib\u003corg.bukkit.util.Vector\u003e bukkitSplineLib = new SplineLib\u003c\u003e() {\n    @Override\n    public Vector convertToVector(org.bukkit.util.Vector value) {\n      return new Vector(value.getX(), value.getY(), value.getZ());\n    }\n\n    @Override\n    public org.bukkit.util.Vector convertFromVector(Vector value) {\n      return new org.bukkit.util.Vector(value.getX(), value.getY(), value.getZ());\n    }\n\n    @Override\n    public BezierVector convertToBezierVector(org.bukkit.util.Vector value) {\n      return new BezierVector(value.getX(), value.getY(), value.getZ(), null, null);\n    }\n\n    @Override\n    public org.bukkit.util.Vector convertFromBezierVector(BezierVector value) {\n      return new org.bukkit.util.Vector(value.getX(), value.getY(), value.getZ());\n    }\n  };\n}\n```\n\nThen you can use the splineLib object to instantiate CurveBuilder objects and to convert Curves to List\u003c\norg.bukkit.util.Vector\u003e. You may consider using one SplineLib per world. This will allow you to instantiate/implement\nit as SplineLib\u003corg.bukkit.Location\u003e and to convert between Locations and internal Vectors directly.\n\n### Builder\n\n#### Instantiating\n\nThe basic way to get a list of vectors from a spline is by using the CurveBuider class. It accepts different parameters\nlike vectors, splines and shapes (Presets in Shapes class) and can be instantiated by calling\n\n```java\nsplineLib.newCurveBuilder(Shapes.star(pose,spikes,smoothing,innerRadius,outerRadius))\n```\n\nThe `.build()` method returns a Curve object. In this case it would simply contain all BezierVectors that were placed in\nthe constructor. Curves and Splines extends Transformables and can be translated, rotated, scaled and mirrored. You can also\ncall `.buildAndConvert()`. SplineLib will automatically convert the built curve by using the registered vector\nconverters. By using the other Builder methods you can define and manipulate the outcome of the build method.\n\nA CurveBuilder is designed to build in two phases. First, it will interpolate the roundness of the spline by using the\ndefined RoundingInterpolator. It will call the according filtering and processing methods that you have defined in the\nbuilder. Then it will execute the spacing phase and interpolate the spacing of every point of the curve that was created\nin the first phase. It will as well call filters and processors.\n\n#### Rounding Interpolator\n\nTo interpolate points and achieve smoothing you will need to provide a rounding interpolator. The library contains\nseveral predefined rounding interpolators that can be found in the Interpolation class.\n\nYou also can create one by implementing the RoundingInterpolator class.\n\nDefine it like so:\n\n```java\nbuilder.withRoundingInterpolator(Interpolation.bezierInterpolation(sampling));\n```\n\nThe sampling parameter defines how many points the interpolator will create. When using the linear interpolator this may\nalso be your final result to build. Linear curve interpolation has a natural spacing interpolation by default.\n\n#### Spacing Interpolators\n\nThe points that are created by Bezier algorithms are not equidistant by default and vary depending on the steepness of\nthe curve. To achieve equidistant points you will need to use a spacing interpolator as well. The sampling of the bezier\nalgorithm defines the smoothness of the curve while the spacing interpolator only moves points along the sampled curve.\nSetting a very low sample resolution before using space interpolators will lead to results like this:\n\n![Sampling](images/interpolation_sampling.png)\n\nSpacing interpolators can be defined by calling:\n```java\nbuilder.withSpacingInterpolator(Interpolation.equidistantInterpolation(distance));\n```\n\nTypes | Description | Example\n--- | --- | ---\nNatural | The natural interpolator divides each segment (from one BezierVector to another) in the given amount of sub-segments. | ![natural](images/interpolation_natural.png)\nEquidistant | The equidistant interpolator sets every point with the provided distance to its neighbour points. | ![equidistant](images/interpolation_equidistant.png)\nAngle | The angular interpolator sets points depending on the steepness of the curve. a straight line will therefore only be visible as a start and end point. | ![angular](images/interpolation_angular.png)\n\n#### Closing the path\n\nWhether a curve is closed or not is defined by its spline. Shaped splines like those from Circles or Stars are closed by\ndefault. New Splines are not closed by default and have to be closed with\n\n```java\nspline.setClosed(true);\n```\n\nThe curve builder also provides a method in case you never had a spline and instantiated a CurveBuilder with a List of\nBezierVectors.\n\n```java\nbuilder.withClosedPath(true);\n```\n\nThis will connect start and end point of the spline before interpolating anything.\n\n#### Filters and Processors\n\nFor each interpolation phase you can provide a point filter. This allows you to filter sample points as well as final\ncurve points. You can also use the processor to filter based on actual BezierVectors or if you want to rotate/mirror the\ncurve between interpolations.\n\n```java\nbuilder\n        .withSpacingFilter(vector-\u003evector.getY()\u003c 100);\n        .withSpacingProcessor(curve-\u003ecurve.mirror(...));\n```\n\n### Creating Phases\n\nTODO\n\n## Examples\n\n### Minecraft Movement Path\n\nIn this example I will show how to use this library to visualize a players movement as a smoothed path. Some parts will\nbe simplyfied but you will get the idea.\n\nFirst I will create a splinelib for this purpose. To keep things simple I will assume this all happens in the same\nworld: `world`.\n\n```java\npublic class PlayerTrack {\n\n  World world; //initialize it somewhere\n  SplineLib\u003cLocation\u003e bukkitSplineLib = new SplineLib\u003c\u003e() {\n    @Override\n    public Vector convertToVector(Location value) {\n      return new Vector(value.getX(), value.getY(), value.getZ());\n    }\n\n    @Override\n    public Location convertFromVector(Vector value) {\n      return new Location(world, value.getX(), value.getY(), value.getZ());\n    }\n\n    @Override\n    public BezierVector convertToBezierVector(Location value) {\n      org.bukkit.util.Vector dir = value.getDirection().normalize();\n      org.bukkit.util.Vector left = value.toVector().subtract(dir);\n      org.bukkit.util.Vector right = value.toVector().add(dir);\n      return new BezierVector(value.getX(), value.getY(), value.getZ(),\n              new Vector(left.getX(), left.getY(), left.getZ()),\n              new Vector(right.getX(), right.getY(), right.getZ()));\n    }\n\n    @Override\n    public Location convertFromBezierVector(BezierVector value) {\n      Location location = new Location(world, value.getX(), value.getY(), value.getZ());\n      location.setDirection(convertFromVector(value.getRightControlPoint().clone().subtract(value)).toVector());\n      return location;\n    }\n  };\n}\n```\n\nTo record a players movement you can run the following code either depending on the players movement or\nin a repeating task:\n\n```java\nimport org.bukkit.entity.Player;\n\npublic class PlayerTrack {\n  private final Spline spline = bukkitSplineLib.newSpline();\n\n  //Call under certain conditions. The converter sets the control points\n  //with a distance of 1. Create new points on the spline\n  //with a distance of around 3-5 blocks to achieve smooth paths.\n  //or change the control point distance in the converter.\n  public void recordLocation(Player player) {\n\n    //convert location to bezier vector\n    //it uses eyelocation because we track the facing direction by converting.\n    //The result will represent the players view like a camera path.\n    spline.add(bukkitSplineLib.convertToBezierVector(player.getEyeLocation()));\n  }\n}\n```\nNow you can display the Spline by converting it into a List of Locations:\n\n```java\npublic class PlayerTrack {\n  private final Spline spline = bukkitSplineLib.newSpline();\n\n  public void displaySpline(Player player) {\n\n    //don't call this many times if the spline does not change - cache the result \n    //instead if you want to respawn the particles with a repeating task\n    List\u003cLocation\u003e locations = bukkitSplineLib.newSplineBuilder(spline)\n            //using 15 samples per ~3 blocks\n            .withRoundingInterpolation(Interpolation.bezierInterpolation(15))\n            //setting distance of final locations to 0.3 blocks\n            .withSpacingInterpolation(Interpolation.equidistantInterpolation(0.3))\n            //convert to List\u003cLocation\u003e directly\n            .buildAndConvert();\n\n    //do this as a repeating task or cache the locations List if you want to summon the\n    //spline particles only at some certain conditions.\n    for (Location location : locations) {\n      player.spawnParticle(Particle.FLAME, location, 1);\n    }\n  }\n}\n```\n\nIf you don't want to interpolate a spline every view ticks but still want to respawn particles at the players location\nyou may want to build it as Curve object (`.build()`) and move it by using the `translate(vectorToNewLocation)`. Then\nyou can convert the Curve by using `List\u003cLocation\u003e locations = bukkitSplineLib.convert(curve);`\n\n\n\n### Minecraft Heart Above Players\n\nIn this example, a heart will appear above a player and will follow him.\nWe will therefore use the bukkitSplineLib of the example above.\n\nWhat we want to achieve:\n- If a player joins, a heart will be placed above his head.\n- It will follow the player for 20 seconds and then disappears.\n- It will be updated twice per second.\n- The heart will adjust its direction based on the players pitch.\n\nWe will need a spline lib and a listener. Also, we need a repeating task to display\nthe particles twice per second.\n````java\nimport org.bukkit.entity.Player;\nimport org.bukkit.event.EventHandler;\nimport org.bukkit.event.Listener;\nimport org.bukkit.event.player.PlayerJoinEvent;\n\npublic class Hearts implements Listener {\n  SplineLib\u003cLocation\u003e splineLib = ...;\n  private int taskId = 0;\n  \n  public Hearts() {\n  \tstartTimer();\n  }\n  \n  @EventHandler\n  public void onJoin(PlayerJoinEvent event) {\n    Player player = event.getPlayer();\n    //create Curve and store it    \n  }\n  \n  public void startTimer() {\n    Bukkit.getScheduler().scheduleSyncRepeatingTask(plugin, () -\u003e {\n        //display particles for all players;\n    }, 0, 10);\n  }\n}\n````\n\nNow we want to create a Heart and store it in a Map:\n\n````java\nimport org.bukkit.entity.Player;\n\nimport java.util.HashMap;\n\npublic class Hearts implements Listener {\n\n  Map\u003cPlayer, Curve\u003e playerHeartMap = new HashMap\u003c\u003e();\n\n  @EventHandler\n  public void onJoin(PlayerJoinEvent event) {\n    Player player = event.getPlayer();\n\n    //create a Pose for the heart to occur (3 blocks above player)\n    Pose pose = splineLib.newPose(player.getLocation(), player.getLocation().getDirection());\n\n    //create the heart curve\n    Curve curve = splineLib.newSplineBuilder(Shapes.heart(pose, /*size*/ 2, /*smoothness*/ 0.5))\n            .withRoundingInterpolation(Interpolation.bezierInterpolation(10))\n            .withSpacingInterpolation(Interpolation.equidistantInterpolation(0.2))\n            .build();\n\n    //store the curve into\n    playerHeartMap.put(player, curve);\n  }\n}\n````","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcubbossa%2Fsplinelib","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fcubbossa%2Fsplinelib","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fcubbossa%2Fsplinelib/lists"}