plyfile

package module
v0.0.0-...-09240d6 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Aug 15, 2016 License: Apache-2.0 Imports: 6 Imported by: 0

README

go-plyfile

GoDoc

Package plyfile provides functions for reading and writing PLY files. The package uses the C plyfile library, originally developed by Greg Turk and released in February 1994. All Go code is provided under the Apache 2.0 license. Greg Turk's code has a separate license (see lib folder).

Pull requests, issues, comments, and feedback in general is always welcome.

Disclaimer

There are probably cleaner, more go-centric ways to write this code. However, this project accomplished several goals. First and foremost, it was a great way to learn more about the relationship between Go programs and C programs when using cgo. The plyfile C library uses a lot of dynamic memory allocation and other C tricks which are not exactly Go-friendly. Most of the Go code copies C memory to Go memory, which is not particularly efficient. Future versions of this library will likely convert some of the original C code to native Go code. But, for a first Go project, this was a great one; a lot of learning happened!

Acknowledgements

A very big thanks is owed to Greg Turk for releasing his original plyfile code. Preserving the flexibility of his original package was a major goal for this project, and none of it would be possible without his well written and well documented C library and accompanying test file.

Installation

Run go get github.com/alexbaden/go-plyfile

The install will fail with the following error:

# github.com/alexbaden/go-plyfile
/usr/bin/ld: cannot find -lplyfile
collect2: error: ld returned 1 exit status# github.com/alexbaden/go-plyfile
/usr/bin/ld: cannot find -lplyfile
collect2: error: ld returned 1 exit status

That's fine, you just need to compile the C code with the included makefile. Head over to the github.com/alexbaden/go-plyfile/lib directory (e.g. cd $GOPATH/src/github.com/alexbaden/go-plyfile/lib ). Compile the C code using make.

Now you can run go build and go install from the parent directory ($GOPATH/src/github.com/alexbaden/go-plyfile).

From there, you should be good to go. But, just to make sure, run go test and verify the two tests (Write and Read) pass.

Basics

The structure of Turk's original code is preserved. The plyfile package makes heavy use of cgo to interface with Turk's code and use his original functions. Note that this means some memory is not tracked by the Go garbage collector. It is critical to properly close PLY files using the PlyClose function!

A comparison of ply_test.go and lib/plytest.c shows nearly identical function calls. Thus, porting a C program that uses Turk's plyfile library should be relatively straightforward. The ply_test.go file shows the process of both writing and reading a PLY file, including how to open a file, describe properties, and write and read data. The basics of writing and reading are also described below.

Writing PLY Files

A full example of writing PLY files is available in ply_test.go. Briefly, the following steps are required:

First, some basic variables must be declared and defined. Namely, a string slice of element names (to define each element to be written to the PLY file). The type of PLY file (ASCII or Binary) must also be specified. In our test example, we generate some data, and set the PLY properties. Properties could be declared in the function body, but using a setting function allows us to re-declare properties in both the Writing and Reading function with little work.

Second, we open the PLY file for writing using the aptly named PlyOpenForWriting function. This function allocates C memory, creates a plyfile object (which we use to track our PLY file through writing), and returns the PLY file version (which will likely always be 1.0). Next, we describe element count, properties, and (optionally) add object info and/or comments. After all this, we can call PlyHeaderComplete, which finalizes the header and writes it to disk.

Third, we setup each element and write the elements to disk. Once elements are written, we can close the PLY file using PlyClose, which frees all allocated C memory and flushes the file to disk (also closing the open file handler). That's it!

Reading PLY Files

A full example of reading PLY files is also available in ply_test.go. Briefly, the following steps are required:

First, we declare our PLY properties and open the PLY file for reading using PlyOpenForReading. PlyOpenForReading returns a CPlyFile object, for tracking our PLY file in future functions, and a list of element names.

Second, we iterate through the returned element names. For each element name, we get the number of elements and number of properties as well as a slice of PLYProperty objects. Next, we allocate Go memory to store the incoming element data, and read the elements. We repeat for each element.

Finally, comments and object info are read from the PLY file, and returned as a slice of strings using the respective reading function.

A note about elements with list properties

The currently element with list property implementation (see Face in ply_test.go) likely needs to be adjusted. The Verts [16]byte array is used to store a pointer to the vertex_indices, and stores a pointer to the vertex_indices on return. Using a 32-bit or 64-bit integer may be better, and will possibly be changed in a future release. However, the basic idea is as follows:

When using a list, we expect to have a dynamic number elements for a given property. The C code expects a pointer to the list of elements, but Go won't package a struct containing pointers. So, we cheat and write the memory location into a byte slice, then pass that byte slice to the C code. As long as we're careful not to garbage collect the memory containing the list of elements while the C code is running, there are no issues.

When reading the list back in, we get a byte slice containing the memory location of the list data we are interested in. ConvertByteSliceToInt32 allows us to write the data stored in C memory, pointed to by the memory address written in the byte slice, to a Go slice. Again, if we're careful not to garbage collect or free memory before reading and converting to a Go object, this method works fine. Since most PLY reading or writing happens in a single function, memory issues should occur infrequently. However, this implementation is a weak point of the current program, and will likely need to be revised.

Documentation

Overview

Package plyfile provides functions for reading and writing PLY files. The package uses the C plyfile library, originally developed by Greg Turk and released in February 1994. All Go code is provided under the Apache 2.0 license. Greg Turk's code has a separate license (see lib folder).

Disclaimer

There are probably cleaner, more go-centric ways to write this code. However, this project accomplished several goals. First and foremost, it was a great way to learn more about the relationship between Go programs and C programs when using cgo. The plyfile C library uses a lot of dynamic memory allocation and other C tricks which are not exactly Go-friendly. Most of the Go code copies C memory to Go memory, which is not particularly efficient. Future versions of this library will likely convert some of the original C code to native Go code. But, for a first Go project, this was a great one; a lot of learning happened!

Acknowledgements

A very big thanks is owed to Greg Turk for releasing his original plyfile code. Preserving the flexibility of his original package was a major goal for this project, and none of it would be possible without his well written and well documented C library and accompanying test file.

Installation

Run

go get github.com/alexbaden/go-plyfile

The install will fail with the following error:

# github.com/alexbaden/go-plyfile
/usr/bin/ld: cannot find -lplyfile
collect2: error: ld returned 1 exit status# github.com/alexbaden/go-plyfile
/usr/bin/ld: cannot find -lplyfile
collect2: error: ld returned 1 exit status

That's fine, you just need to compile the C code with the included makefile. Head over to the github.com/alexbaden/go-plyfile/lib directory:

cd $GOPATH/src/github.com/alexbaden/go-plyfile/lib

Compile the C code using make.

Now you can run go build and go install from the parent directory:

$GOPATH/src/github.com/alexbaden/go-plyfile

From there, you should be good to go. But, just to make sure, run go test and verify the two tests (Write and Read) pass.

Basics

The structure of Turk's original code is preserved. The plyfile package makes heavy use of cgo to interface with Turk's code and use his original functions. Note that this means some memory is not tracked by the Go garbage collector. It is critical to properly close PLY files using the PlyClose function!

A comparison of ply_test.go and lib/plytest.c shows nearly identical function calls. Thus, porting a C program that uses Turk's plyfile library should be relatively straightforward. The ply_test.go file shows the process of both writing and reading a PLY file, including how to open a file, describe properties, and write and read data. The basics of writing and reading are also described below.

Writing PLY Files

A full example of writing PLY files is available in ply_test.go. Briefly, the following steps are required:

First, some basic variables must be declared and defined. Namely, a string slice of element names (to define each element to be written to the PLY file). The type of PLY file (ASCII or Binary) must also be specified. In our test example, we generate some data, and set the PLY properties. Properties could be declared in the function body, but using a setting function allows us to re-declare properties in both the Writing and Reading function with little work.

Second, we open the PLY file for writing using the aptly named PlyOpenForWriting function. This function allocates C memory, creates a plyfile object (which we use to track our PLY file through writing), and returns the PLY file version (which will likely always be 1.0). Next, we describe element count, properties, and (optionally) add object info and/or comments. After all this, we can call PlyHeaderComplete, which finalizes the header and writes it to disk.

Third, we setup each element and write the elements to disk. Once elements are written, we can close the PLY file using PlyClose, which frees all allocated C memory and flushes the file to disk (also closing the open file handler). That's it!

Reading PLY Files

A full example of reading PLY files is also available in ply_test.go. Briefly, the following steps are required:

First, we declare our PLY properties and open the PLY file for reading using PlyOpenForReading. PlyOpenForReading returns a CPlyFile object, for tracking our PLY file in future functions, and a list of element names.

Second, we iterate through the returned element names. For each element name, we get the number of elements and number of properties as well as a slice of PLYProperty objects. Next, we allocate Go memory to store the incoming element data, and read the elements. We repeat for each element.

Finally, comments and object info are read from the PLY file, and returned as a slice of strings using the respective reading function.

A note about elements with list properties

The currently element with list property implementation (see Face in ply_test.go) likely needs to be adjusted. The Verts [16]byte array is used to store a pointer to the vertex_indices, and stores a pointer to the vertex_indices on return. Using a 32-bit or 64-bit integer may be better, and will possibly be changed in a future release. However, the basic idea is as follows:

When using a list, we expect to have a dynamic number elements for a given property. The C code expects a pointer to the list of elements, but Go won't package a struct containing pointers. So, we cheat and write the memory location into a byte slice, then pass that byte slice to the C code. As long as we're careful not to garbage collect the memory containing the list of elements while the C code is running, there are no issues.

When reading the list back in, we get a byte slice containing the memory location of the list data we are interested in. ConvertByteSliceToInt32 allows us to write the data stored in C memory, pointed to by the memory address written in the byte slice, to a Go slice. Again, if we're careful not to garbage collect or free memory before reading and converting to a Go object, this method works fine. Since most PLY reading or writing happens in a single function, memory issues should occur infrequently. However, this implementation is a weak point of the current program, and will likely need to be revised.

Index

Constants

View Source
const (
	PLY_ASCII     = 1 /* ascii PLY file */
	PLY_BINARY_BE = 2 /* binary PLY file, big endian */
	PLY_BINARY_LE = 3 /* binary PLY file, little endian */

	PLY_OKAY  = 0  /* ply routine worked okay */
	PLY_ERROR = -1 /* error in ply routine */

	/* scalar data types supported by PLY format */
	PLY_START_TYPE = 0
	PLY_CHAR       = 1
	PLY_SHORT      = 2
	PLY_INT        = 3
	PLY_UCHAR      = 4
	PLY_USHORT     = 5
	PLY_UINT       = 6
	PLY_FLOAT      = 7
	PLY_DOUBLE     = 8
	PLY_END_TYPE   = 9

	PLY_SCALAR = 0
	PLY_LIST   = 1
)

PLY definitions, for consistency with C code.

Variables

This section is empty.

Functions

func ByteSliceToPointer

func ByteSliceToPointer(bslice []byte) (ptr uintptr)

ByteSliceToPointer takes a byte slice containing a pointer (necessary for passing pointers back and forth to C programs as part of a struct) and reads the pointer, returning it as a uintptr. Note that typically this function will be called on byte arrays, and slicing the array ('[:]') when passing it to the function will be necessary.

func ConvertByteSliceToInt32

func ConvertByteSliceToInt32(bslice []byte, num_elems int) (ret []int32)

ConvertByteSliceToInt32 takes a byte slice containing a memory location and a number of integer elements and returns an int32 array made up of the contents of the memory pointed to by the byte slice (to a maximum of num_elems elements).

func PlyClose

func PlyClose(plyfile CPlyFile)

PlyClose closes the open plyfile, specified by the CPlyFile object. Note that the PLY file memory is tracked by C, not by Go, and calling this function is necessary to free memory associated with the open PLY file.

func PlyDescribeProperty

func PlyDescribeProperty(plyfile CPlyFile, element_name string, prop PlyProperty)

PlyDescribeProperty describes a property of an element.

func PlyElementCount

func PlyElementCount(plyfile CPlyFile, element_name string, nelems int)

PlyElementCount specifies the number of elements that are about to be written.

func PlyGetComments

func PlyGetComments(plyfile CPlyFile) []string

PlyGetComments returns the comments contained in the open PLY file header.

func PlyGetElement

func PlyGetElement(plyfile CPlyFile, element interface{}, size uintptr)

PlyGetElement retrieves an element from the PLY file. The properties returned must be specified by PlyGetProperty before calling PlyGetElement.

func PlyGetObjInfo

func PlyGetObjInfo(plyfile CPlyFile) []string

PlyGetObjInfo returns the object info contained in the open PLY file header.

func PlyGetProperty

func PlyGetProperty(plyfile CPlyFile, elem_name string, prop PlyProperty)

PlyGetProperty specifies a property of an element that should be returned with a call to PlyGetElement. Note that PlyGetProperty must be called before PlyGetElement, and can be called multiple times (for each PLYProperty an element contains).

func PlyHeaderComplete

func PlyHeaderComplete(plyfile CPlyFile)

PlyHeaderComplete signals that the PLY header is fully described and flushes it to disk.

func PlyPutComment

func PlyPutComment(plyfile CPlyFile, comment string)

PlyPutComment writes the specified comment into the PLY file header.

func PlyPutElement

func PlyPutElement(plyfile CPlyFile, element interface{})

PlyPutElement writes an element to the PLY file. The type of element is specified by PlyPutElementSetup, which must be called first.

func PlyPutElementSetup

func PlyPutElementSetup(plyfile CPlyFile, element_name string)

PlyPutElementSetup specifies which element is about to be written. This should be called prior to PlyPutElement.

func PlyPutObjInfo

func PlyPutObjInfo(plyfile CPlyFile, obj_info string)

PlyPutObjInfo writes the specified object info string into the PLY file header.

func PointerToByteSlice

func PointerToByteSlice(ptr uintptr) []byte

PointerToByteSlice takes a memory location and stores it in a byte slice, which is returned. Note that this function is typically very unsafe in Go programs. Use caution!

func ReadPLYListInt32

func ReadPLYListInt32(ptr uintptr, num_elems int) []int32

ReadPLYListInt32 takes as input a pointer (which should be pointing to C memory) and a number of elements and reads an arbitrary size array into an int32 slice.

Types

type CPlyElement

type CPlyElement *C.struct_PlyElement

type CPlyFile

type CPlyFile *C.struct_PlyFile

func PlyOpenForReading

func PlyOpenForReading(filename string) (CPlyFile, []string)

PlyOpenForReading opens a PLY file (specified by filename) and reads in the header information. The returned PlyFile object is used to access header information and data stored in the PLY file.

func PlyOpenForWriting

func PlyOpenForWriting(filename string, nelems int, elem_names []string, file_type int, version *float32) CPlyFile

PlyOpenForWriting creates a new PLY file (called filename) and writes in header information, specified by the other parameters. The returned PlyFile object is used to access header information and data stored in the PLY file.

func PlyUseExistingForWriting

func PlyUseExistingForWriting(fp *os.File, nelems int, elem_names []string, file_type int, version *float32) CPlyFile

PlyUseExistingForWriting uses an existing file pointer to create a new PLY file and writes in header information, specified by the other parameters. The returned PlyFile object is used to access header information and data stored in the PLY file.

type CPlyProperty

type CPlyProperty C.struct_PlyProperty

type PlyProperty

type PlyProperty struct {
	Name          string /* property name */
	External_type int    /* file's data type */
	Internal_type int    /* program's data type */
	Offset        int    /* offset bytes of prop in a struct */

	Is_list        int /* 1 = list, 0 = scalar */
	Count_external int /* file's count type */
	Count_internal int /* program's count type */
	Count_offset   int /* offset byte for list count */
}

func PlyGetElementDescription

func PlyGetElementDescription(plyfile CPlyFile, element_name string) ([]PlyProperty, int, int)

PlyGetElementDescription reads information about a specified element from an open PLY file.

func (*PlyProperty) FromC

func (prop *PlyProperty) FromC(cprop CPlyProperty)

FromC converts a PlyProperty C structure (passed from a C function to the Go program) to a Go structure

func (*PlyProperty) ToC

func (prop *PlyProperty) ToC() CPlyProperty

ToC converts a PlyProperty go structure to a PlyProperty C structure for passing to C functions

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL