Table of Contents

This is not final, but meant as a place to collect our ideas about a redesign of the hook implementation. See also this forum topic.

The current implementation is quite complex. There are three fields in ControlPoint used to represent hooks:

private ControlPoint cpParentHook; private ControlPoint cpChildHook; private float fHookPos;

When a hook **H** is added between two ControlPoints **A** and **B**, a new curve **C**,**D**,**E** is created, and **H** is attached to **D**:

cp | next | prev | next attached | prev attached | child hook | parent hook | hook pos |
---|---|---|---|---|---|---|---|

A | B | C | -1 | ||||

B | A | -1 | |||||

C | D | A | 0.0 | ||||

D | E | C | H | 0.5 | |||

E | D | E | 1.0 | ||||

H | x | D | -1 |

The curve **C**,**D**,**E** is an exact copy of the segment **A**, **B** (D’s position and the tangents are computed using de Casteljau’s algorithm), and **H** is simply attached to **D**.

The image above shows three curves (x, y and z) and a hook curve (w) from point C to D, where D is a hook on curve y between points A and B (the figure shows only the “head”-points, not the attached points). For point D two tangents need to be computed. The first one is the tangent on curve y, which is quite easy: The position of point D and all the tangents on the curve segments A-D and D-B can be computed by using De_Casteljau's_algorithm:

The tangents of the curve segment C-D (curve w) are more difficult to compute: On point C, the tangents are computed as usual, but on point D, the tangent should be the (weighted) average of the tangents of point A (curve x) and point B (curve z) - shown in blue in the image on top. The method *public void computeTargetHookBorderTangents(Vector3f v3Direction, Vector3f v3Start, Vector3f v3End)* returns the two tangents to be averaged when called on a “target hook”, i.e. a point that is attached to a hook.
It takes the estimated direction of the tangent (i.e. the vector C-D) as input parameters and returns the two border tangents (v3Start and v3End) - i.e. the blue tangents in the top image. It does this by cycling through all curves goint through points A and B, respectively and returns the tangents that are closest to the v3Direction vector. Note that it does not take the curve y (A-B) into account, so under normal circumstances (only two curves cross at A and B) there is only one possible solution.

The method *computeTargetHookBorderTangents* is called by *private Vector3f getTargetHookTangent(Vector3f v3Direction)*, which averages the two tangents (weighted by the hook position).

To make the code easier to maintain, a new hook representation was proposed: Hooks should (like regular ControlPoints) be part of the curve. *cpChildHook* and *cpParentHook* would no longer be needed. A hook would be identified by it’s *fHookPos* value. If it’s greater than 0 and less than 1 it is a hook. Non hooks could use 0.
So a hook **H** between ControlPoints **A** and **B** would simply be attached to a point **C**, that is on the curve connecting **A** an **B** and has it’s *fHookPos* set e.g. to 0.5:

cp | next | prev | next attached | prev attached | hook pos |
---|---|---|---|---|---|

A | C | 0 | |||

C | B | A | H | 0.5 | |

B | C | 0 | |||

H | x | C | 0 |

Here, **C** is simply inserted between **A** and **B**, but it has a “flag” set, identifying it as a hook.

*xml()*needs to be adapted.- The fields
*cpParentHook*and*cpChildHook*can be discarded. - To be “backward compatible” with other parts of the code,
*ControlPoint getNext()*and*ControlPoint getPrev()*should be modified to return the next and previous**non hook**CPs, respectively. - New
*ControlPoint getNextHook()*and*ControlPoint getPrevHook()*methods are needed that return the next and previous**hook**CPs, respectively. *Point3f getInTangent()*and*Point3f getOutTangent()*need to be changed, new methods*Point3f getInHookTangent()*and*Point3f getOutHookTangent()*are required.*Point3f getPosition()*must be adapted.- all
*getReference…()*methods must be adapted or redesigned, see optional changes below…

Currently there are two methods for each operation, one for the current pose, the other for the reference pose, e.g. getPosition() vs. getReferencePosition(). Much of the code is duplicated, it should be shared and thus moved to helper methods.

- v
*oid computePatches()*and*void computePatches(JPatchActionEdit edit)*, respectively

A new method that allows to efficiently run the patchfinder for just a single ControlPoint - this method could be called whenever a controlPoint was welded by a user right-click to automatically add possible new patches.

- the methods
*Point3f[] coonsPatch()*and*Point3f[] referenceCoonsPatch()*need to be adapted

- AbstractClone ?
- AtomicChangeControlPoint.ParentHook (can be discarded)
- AtomicChangeControlPoint.ChildHook (can be discarded)
- AtomicDeleteControlPointFromCurve (needs to be adapted - what should be done with neighbor hooks?)
- AtomicInsertControlPoint (needs to be adapted - neighbor hooks positions need to be recomputed? should it be allowed to insert a point next to a hook at all?)
- AtomicRemoveControlPointFromCurve ?
- AtomicReverseCurve (needs to be adapted)
- CompoundAppendControlPoints ?
- CompoundAutoMirror ?
- CompoundClone ?
- CompoundConvertHookToCp ?
- CompoundDelete ?
- CompoundDeleteControlPoint ?
- CompoundDropControlPoint ?
- CompoundDropCurve ?
- CompoundExtrude ?
- CompoundHook ?
- CompoundLathe ?
- CompoundRemove ?
- CompoundRemoveControlPoint ?
- CompoundRemoveControlPointFromEntities ?
- CompoundRemoveCurveSegment ?
- CompoundWeldControlPoints ?

- JPatchImport
- AnimationMasterImport