# cpf3d
> A python library to read and edit [3cpf](https://github.com/ruelalarcon/3cpf) files. Requires
> python 3.8.
**Features**
- Read 3cpf files into easily usable data
- Create new points and frames
- Apply basic position, scale, and rotation transformations to all points in a 3cpf file
- Write 3cpf data into 3cpf files
## Installation
The package can be installed with `pip`.
```bash
pip install cpf3d
```
## Usage
### Reading files
The `cpf3d.load` function can be used to load a 3cpf files as a `cpf3d.PointFrames` object, which has points and frames.
```python
import cpf3d
# Load a 3cpf file
pf = cpf3d.load('miku_example.3cpf')
# From here, we can access any necessary data
print('# of Points:', len(pf.points))
print('# of Frames:', len(pf.frames))
# Point colors
print('\nColors of First 5 Points:')
for point in pf.points[:5]:
print(point.color)
# Position of specific point at specific frame
print('\nPositions of Point 0 Throughout First 5 Frames:')
for i in range(5):
print(pf.get_position(0, i))
```
Output:
```
# of Points: 600
# of Frames: 60
Colors of First 5 Points:
(112, 112, 112)
(112, 112, 112)
(0, 0, 0)
(112, 112, 112)
(112, 112, 112)
Positions of Point 0 Throughout First 5 Frames:
[-0.01653824 0.05377164 1.10009 ]
[-0.01205087 0.05788074 1.0995283 ]
[-0.00502312 0.06201064 1.1008564 ]
[0.00529542 0.06594937 1.1022888 ]
[0.01859665 0.06944766 1.1035271 ]
```
If your use-case uses a different coordinate order (XYZ vs. YXZ for example), you can load a 3cpf with any coordinate order of your choice.
```python
import cpf3d
# Load a 3cpf file, with dimensions in the order of xzy, rather than the default xyz
pf = cpf3d.load('miku_example.3cpf', 'xzy')
```
### Editing and Creating 3cpf Files
You can edit instances of `cpf3d.PointFrames` and save them as 3cpf files.
```python
import cpf3d
# Editing an existing 3cpf file
pf = nbtlib.load('miku_example.3cpf')
# Rotate entire animation 90 degrees along the Z-axis
# Scale to half size across all dimensions
# And move 1 along the X-axis
pf.apply_rotation(0, 0, 90) \
.apply_scale(.5, .5, .5) \
.apply_offset(1, 0, 0)
# Save the now-transformed point frames into a new file
pf.save('miku_example_transformed.3cpf')
```
Or write a 3cpf file from scratch.
```python
import cpf3d
from cpf3d import PointFrames, Point, Frame
# Creating a 3cpf file from scratch
custom_pf = PointFrames()
point_r = Point(255, 0, 0) # Red point
point_g = Point(0, 255, 0) # Green point
custom_pf.add_point(point_r)
custom_pf.add_point(point_g)
# First frame: Red point at 1,1,1. Green point at 2,2,2
frame_1 = Frame([[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]])
# Second frame: Red point at 2,2,2. Green point at 4,4,4
frame_2 = Frame([[2.0, 2.0, 2.0], [4.0, 4.0, 4.0]])
custom_pf.add_frame(frame_1)
custom_pf.add_frame(frame_2)
# Scale it all by ten times
custom_pf.apply_scale(10, 10, 10)
# Export to a 3cpf file
custom_pf.save('my_pointframes.3cpf')
```
### Adding Points or Frames to Existing 3cpf Data
There are a variety of restrictions related to adding points or frames to existing 3cpf animations.
**Firstly,** you cannot add frames *before* adding any points.
```python
pf = PointFrames()
# Will cause an error, as there are no points to attach this positional data to
frame = Frame([[1.0, 2.0, 3.0]])
```
**Secondly,** when adding new frames, you must have one positional entry for each point.
```python
# Assume this 3cpf file contains 2 points
pf = cpf3d.load('2points.3cpf')
# Will cause an error, as we are adding a frame with 1 position, but there are 2 points
frame = Frame([[1.0, 2.0, 3.0]])
pf.add_frame(frame)
# Similarly, this would also error
frame = Frame([[1.0, 2.0, 3.0], [1.0, 2.0, 3.0], [1.0, 2.0, 3.0]])
pf.add_frame(frame)
```
**Lastly,** when adding new points, if you already have frames in your 3cpf file, you must provide positions for your new point at each frame.
```python
# Assume this 3cpf file contains 2 points and 2 frames
pf = cpf3d.load('2points2frames.3cpf')
# Will cause an error, as there are already frames in this 3cpf animation
point = Point(255, 255, 255)
pf.add_point(point)
```
We would instead need to do something like this:
```python
pf = cpf3d.load('2points2frames.3cpf')
point = Point(255, 255, 255)
# This point moves from 1,1,1 to 2,2,2 through frames 0 and 1
positions = [[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]]
pf.add_frame(point, positions) # This works fine
```
This is necessary due to the nature of 3cpf files, in that each point must have corresponding positional data within each frame chunk.
## Contributing
Contributions are welcome. This project is packaged with python's built-in [setuptools](https://setuptools.pypa.io/en/latest/).
To install this package locally for development, you can clone or download this repository and navigate to it in your terminal.
You should now be able to install it locally, including development dependencies.
```bash
pip install -e .[dev]
```
You can run the tests by simply executing pytest from the top directory.
```bash
pytest
```
Raw data
{
"_id": null,
"home_page": "https://github.com/ruelalarcon/cpf3d",
"name": "cpf3d",
"maintainer": "",
"docs_url": null,
"requires_python": ">=3.8",
"maintainer_email": "",
"keywords": "3cpf,point,cloud,frames",
"author": "Ruel Nathaniel Alarcon",
"author_email": "ruelnalarcon@gmail.com",
"download_url": "https://files.pythonhosted.org/packages/86/67/f83c0ca2db91e91ac28f649d3911a44639c98255226281d992abfddd89f7/cpf3d-1.0.0.tar.gz",
"platform": null,
"description": "# cpf3d\r\n\r\n> A python library to read and edit [3cpf](https://github.com/ruelalarcon/3cpf) files. Requires\r\n> python 3.8.\r\n\r\n**Features**\r\n\r\n- Read 3cpf files into easily usable data\r\n- Create new points and frames\r\n- Apply basic position, scale, and rotation transformations to all points in a 3cpf file\r\n- Write 3cpf data into 3cpf files\r\n\r\n## Installation\r\n\r\nThe package can be installed with `pip`.\r\n\r\n```bash\r\npip install cpf3d\r\n```\r\n\r\n## Usage\r\n\r\n### Reading files\r\n\r\nThe `cpf3d.load` function can be used to load a 3cpf files as a `cpf3d.PointFrames` object, which has points and frames.\r\n\r\n```python\r\nimport cpf3d\r\n\r\n# Load a 3cpf file\r\npf = cpf3d.load('miku_example.3cpf')\r\n\r\n# From here, we can access any necessary data\r\nprint('# of Points:', len(pf.points))\r\nprint('# of Frames:', len(pf.frames))\r\n\r\n# Point colors\r\nprint('\\nColors of First 5 Points:')\r\nfor point in pf.points[:5]:\r\n print(point.color)\r\n\r\n# Position of specific point at specific frame\r\nprint('\\nPositions of Point 0 Throughout First 5 Frames:')\r\nfor i in range(5):\r\n print(pf.get_position(0, i))\r\n```\r\nOutput:\r\n```\r\n# of Points: 600\r\n# of Frames: 60\r\n\r\nColors of First 5 Points:\r\n(112, 112, 112)\r\n(112, 112, 112)\r\n(0, 0, 0)\r\n(112, 112, 112)\r\n(112, 112, 112)\r\n\r\nPositions of Point 0 Throughout First 5 Frames:\r\n[-0.01653824 0.05377164 1.10009 ]\r\n[-0.01205087 0.05788074 1.0995283 ]\r\n[-0.00502312 0.06201064 1.1008564 ]\r\n[0.00529542 0.06594937 1.1022888 ]\r\n[0.01859665 0.06944766 1.1035271 ]\r\n```\r\n\r\nIf your use-case uses a different coordinate order (XYZ vs. YXZ for example), you can load a 3cpf with any coordinate order of your choice.\r\n```python\r\nimport cpf3d\r\n\r\n# Load a 3cpf file, with dimensions in the order of xzy, rather than the default xyz\r\npf = cpf3d.load('miku_example.3cpf', 'xzy')\r\n```\r\n\r\n### Editing and Creating 3cpf Files\r\n\r\nYou can edit instances of `cpf3d.PointFrames` and save them as 3cpf files.\r\n\r\n```python\r\nimport cpf3d\r\n\r\n# Editing an existing 3cpf file\r\npf = nbtlib.load('miku_example.3cpf')\r\n\r\n# Rotate entire animation 90 degrees along the Z-axis\r\n# Scale to half size across all dimensions\r\n# And move 1 along the X-axis\r\npf.apply_rotation(0, 0, 90) \\\r\n .apply_scale(.5, .5, .5) \\\r\n .apply_offset(1, 0, 0)\r\n\r\n# Save the now-transformed point frames into a new file\r\npf.save('miku_example_transformed.3cpf')\r\n```\r\n\r\nOr write a 3cpf file from scratch.\r\n```python\r\nimport cpf3d\r\nfrom cpf3d import PointFrames, Point, Frame\r\n\r\n# Creating a 3cpf file from scratch\r\ncustom_pf = PointFrames()\r\n\r\npoint_r = Point(255, 0, 0) # Red point\r\npoint_g = Point(0, 255, 0) # Green point\r\n\r\ncustom_pf.add_point(point_r)\r\ncustom_pf.add_point(point_g)\r\n\r\n# First frame: Red point at 1,1,1. Green point at 2,2,2\r\nframe_1 = Frame([[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]])\r\n\r\n# Second frame: Red point at 2,2,2. Green point at 4,4,4\r\nframe_2 = Frame([[2.0, 2.0, 2.0], [4.0, 4.0, 4.0]])\r\ncustom_pf.add_frame(frame_1)\r\ncustom_pf.add_frame(frame_2)\r\n\r\n# Scale it all by ten times\r\ncustom_pf.apply_scale(10, 10, 10)\r\n\r\n# Export to a 3cpf file\r\ncustom_pf.save('my_pointframes.3cpf')\r\n```\r\n\r\n### Adding Points or Frames to Existing 3cpf Data\r\n\r\nThere are a variety of restrictions related to adding points or frames to existing 3cpf animations.\r\n\r\n**Firstly,** you cannot add frames *before* adding any points.\r\n```python\r\npf = PointFrames()\r\n\r\n# Will cause an error, as there are no points to attach this positional data to\r\nframe = Frame([[1.0, 2.0, 3.0]])\r\n```\r\n\r\n**Secondly,** when adding new frames, you must have one positional entry for each point.\r\n```python\r\n# Assume this 3cpf file contains 2 points\r\npf = cpf3d.load('2points.3cpf')\r\n\r\n# Will cause an error, as we are adding a frame with 1 position, but there are 2 points\r\nframe = Frame([[1.0, 2.0, 3.0]])\r\npf.add_frame(frame)\r\n\r\n# Similarly, this would also error\r\nframe = Frame([[1.0, 2.0, 3.0], [1.0, 2.0, 3.0], [1.0, 2.0, 3.0]])\r\npf.add_frame(frame)\r\n```\r\n\r\n**Lastly,** when adding new points, if you already have frames in your 3cpf file, you must provide positions for your new point at each frame.\r\n\r\n```python\r\n# Assume this 3cpf file contains 2 points and 2 frames\r\npf = cpf3d.load('2points2frames.3cpf')\r\n\r\n# Will cause an error, as there are already frames in this 3cpf animation\r\npoint = Point(255, 255, 255)\r\npf.add_point(point)\r\n```\r\n\r\nWe would instead need to do something like this:\r\n```python\r\npf = cpf3d.load('2points2frames.3cpf')\r\n\r\npoint = Point(255, 255, 255)\r\n\r\n# This point moves from 1,1,1 to 2,2,2 through frames 0 and 1\r\npositions = [[1.0, 1.0, 1.0], [2.0, 2.0, 2.0]]\r\n\r\npf.add_frame(point, positions) # This works fine\r\n```\r\n\r\nThis is necessary due to the nature of 3cpf files, in that each point must have corresponding positional data within each frame chunk.\r\n\r\n## Contributing\r\n\r\nContributions are welcome. This project is packaged with python's built-in [setuptools](https://setuptools.pypa.io/en/latest/).\r\n\r\nTo install this package locally for development, you can clone or download this repository and navigate to it in your terminal.\r\n\r\nYou should now be able to install it locally, including development dependencies.\r\n\r\n```bash\r\npip install -e .[dev]\r\n```\r\n\r\nYou can run the tests by simply executing pytest from the top directory.\r\n\r\n```bash\r\npytest\r\n```\r\n",
"bugtrack_url": null,
"license": "MIT",
"summary": "A package for reading and writing 3cpf files.",
"version": "1.0.0",
"project_urls": {
"Homepage": "https://github.com/ruelalarcon/cpf3d",
"Repository": "https://github.com/ruelalarcon/cpf3d"
},
"split_keywords": [
"3cpf",
"point",
"cloud",
"frames"
],
"urls": [
{
"comment_text": "",
"digests": {
"blake2b_256": "8edc1f85c7ac8b74d4bcb0714035237ccf5b2ea40652fa802fac3239ee3f652e",
"md5": "d724d29e6d74245a7ba1f2ceb046bf4a",
"sha256": "79f6922ff820844570cfa065a869c4c4303d72a3b6adacb62e2c1c315b4300eb"
},
"downloads": -1,
"filename": "cpf3d-1.0.0-py3-none-any.whl",
"has_sig": false,
"md5_digest": "d724d29e6d74245a7ba1f2ceb046bf4a",
"packagetype": "bdist_wheel",
"python_version": "py3",
"requires_python": ">=3.8",
"size": 6542,
"upload_time": "2024-02-23T02:53:34",
"upload_time_iso_8601": "2024-02-23T02:53:34.597334Z",
"url": "https://files.pythonhosted.org/packages/8e/dc/1f85c7ac8b74d4bcb0714035237ccf5b2ea40652fa802fac3239ee3f652e/cpf3d-1.0.0-py3-none-any.whl",
"yanked": false,
"yanked_reason": null
},
{
"comment_text": "",
"digests": {
"blake2b_256": "8667f83c0ca2db91e91ac28f649d3911a44639c98255226281d992abfddd89f7",
"md5": "b7c11842c8568819676e3e4740459c9c",
"sha256": "27c0c394ba60036cbcc1517917e8025b2d26c9d419b52b5c986a3c75204c45be"
},
"downloads": -1,
"filename": "cpf3d-1.0.0.tar.gz",
"has_sig": false,
"md5_digest": "b7c11842c8568819676e3e4740459c9c",
"packagetype": "sdist",
"python_version": "source",
"requires_python": ">=3.8",
"size": 7248,
"upload_time": "2024-02-23T02:53:36",
"upload_time_iso_8601": "2024-02-23T02:53:36.826304Z",
"url": "https://files.pythonhosted.org/packages/86/67/f83c0ca2db91e91ac28f649d3911a44639c98255226281d992abfddd89f7/cpf3d-1.0.0.tar.gz",
"yanked": false,
"yanked_reason": null
}
],
"upload_time": "2024-02-23 02:53:36",
"github": true,
"gitlab": false,
"bitbucket": false,
"codeberg": false,
"github_user": "ruelalarcon",
"github_project": "cpf3d",
"travis_ci": false,
"coveralls": false,
"github_actions": false,
"lcname": "cpf3d"
}