package Command; import java.util.ArrayList; import Common.Box2; import Common.Box3; import Common.Matrix3; import Common.Matrix4; import Common.Vector3f; import LDraw.Support.LDrawDirective; import LDraw.Support.MatrixMath; import LDraw.Support.type.CacheFlagsT; public class LDrawDrawableElement extends LDrawDirective implements LDrawColorable, LDrawMovableDirective { /** * @uml.property name="color" * @uml.associationEnd */ protected LDrawColor color; /** * @uml.property name="hidden" */ protected boolean hidden; // YES if we don't draw this. // ========== init // ============================================================== // // Purpose: Create a fresh object. This is the default initializer. // // ============================================================================== public LDrawDrawableElement init() { super.init(); hidden = false; return this; }// end init // ========== boundingBox3 // ====================================================== // // Purpose: Returns the minimum and maximum points of the box which // perfectly contains this object. // // ============================================================================== public Box3 boundingBox3() { Box3 bounds = Box3.getInvalidBox(); // You shouldn't be here. Look in a subclass. return bounds; }// end boundingBox3 // ========== projectedBoundingBoxWithModelView:projection:view: // ================ // // Purpose: Returns the 2D projection (you should ignore the z) of the // object's bounds. // // ============================================================================== public Box3 projectedBoundingBoxWithModelView(Matrix4 modelView, Matrix4 projection, Box2 viewport) { Box3 bounds = boundingBox3(); Vector3f windowPoint = Vector3f.getZeroVector3f(); Box3 projectedBounds = Box3.getInvalidBox(); if (MatrixMath.V3EqualBoxes(bounds, Box3.getInvalidBox()) == false) { // front lower left windowPoint = MatrixMath.V3Project(bounds.getMin(), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // front lower right windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMax().getX(), bounds.getMin().getY(), bounds.getMin().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // front upper right windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMax().getX(), bounds.getMax().getY(), bounds.getMin().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // front upper left windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMin().getX(), bounds.getMax().getY(), bounds.getMin().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // back lower left windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMin().getX(), bounds.getMin().getY(), bounds.getMax().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // back lower right windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMax().getX(), bounds.getMin().getY(), bounds.getMax().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // back upper right windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMax().getX(), bounds.getMax().getY(), bounds.getMax().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); // back upper left windowPoint = MatrixMath.V3Project(MatrixMath.V3Make( bounds.getMin().getX(), bounds.getMax().getY(), bounds.getMax().getZ()), modelView, projection, viewport); projectedBounds = MatrixMath.V3UnionBoxAndPoint(projectedBounds, windowPoint); } return projectedBounds; }// end projectedBoundingBoxWithModelView:projection:view: // ========== isHidden // ========================================================== // // Purpose: Returns whether this element will be drawn or not. // // ============================================================================== /** * @return * @uml.property name="hidden" */ public boolean isHidden() { return hidden; }// end isHidden // ========== LDrawColor // ======================================================== // // Purpose: Returns the LDraw color code of the receiver. // // ============================================================================== public LDrawColor getLDrawColor() { return color; }// end LDrawColor // ========== position // ========================================================== // // Purpose: Returns some position for the element. This is used by // drag-and-drop. This is not necessarily human-usable information. // // ============================================================================== public Vector3f position() { return Vector3f.getZeroVector3f(); }// end position // #pragma mark - // ========== setHidden: // ======================================================== // // Purpose: Sets whether this part will be drawn, or whether it will be // skipped during drawing. This setting only affects drawing; // hidden parts will always be written out. Also, note that // hiddenness is a temporary state; it is not saved and restored. // // ============================================================================== /** * @param flag * @uml.property name="hidden" */ public void setHidden(boolean flag) { if (hidden != flag) { hidden = flag; if(enclosingDirective()!=null) enclosingDirective().setVertexesNeedRebuilding(); invalCache(CacheFlagsT.CacheFlagBounds); invalCache(CacheFlagsT.DisplayList); } }// end setHidden: // ========== setLDrawColor: // ==================================================== // // Purpose: Sets the color of this element. // // ============================================================================== public void setLDrawColor(LDrawColor newColor) { color = newColor; invalCache(CacheFlagsT.DisplayList); // Needed to force anyone who is // cached to recompute the new // DL with possibly baked color! }// end setLDrawColor: // #pragma mark - // #pragma mark MOVEMENT // #pragma mark - // ========== displacementForNudge: // ============================================= // // Purpose: Returns the amount by which the element wants to move, given a // "nudge" in the specified direction. A "nudge" is generated by // pressing the arrow keys. If they feel it appropriate, subclasses // are perfectly welcome to scale this value. (LDrawParts do this.) // // ============================================================================== public Vector3f displacementForNudge(Vector3f nudgeVector) { // possibly refined by subclasses. return nudgeVector; }// end displacementForNudge: // ========== moveBy: // =========================================================== // // Purpose: Displace the receiver by the given amounts in each direction. // The amounts in moveVector or relative to the element's current // location. // // Subclasses are required to move by exactly this amount. Any // adjustments they wish to make need to be returned in // -displacementForNudge:. // // ============================================================================== public void moveBy(Vector3f moveVector) { // implemented by subclasses. }// end moveBy: // ========== position:snappedToGrid: // =========================================== // // Purpose: Orients position at discrete points separated by the given grid // spacing. // // Notes: This method may be overridden by subclasses to provide more // intelligent grid alignment. // // This method is provided mainly as a service to drag-and-drop. // In the case of LDrawParts, you should generally avoid this // method in favor of // -[LDrawPart components:snappedToGrid:minimumAngle:]. // // ============================================================================== public Vector3f position(Vector3f position, float gridSpacing) { position.setX(Math.round(position.getX() / gridSpacing) * gridSpacing); position.setY(Math.round(position.getY() / gridSpacing) * gridSpacing); position.setZ(Math.round(position.getZ() / gridSpacing) * gridSpacing); return position; }// end position:snappedToGrid: // #pragma mark - // #pragma mark UTILITIES // #pragma mark - // ========== flattenIntoLines:triangles:quadrilaterals:other:currentColor: // ===== // // Purpose: Appends the directive into the appropriate container. // // Notes: This is used to flatten a complicated hiearchy of primitives and // part references to files containing yet more primitives into a // single flat list, which may be drawn to produce a shape visually // identical to the original structure. The flattened structure, // however, has the advantage that it is much faster to traverse // during drawing. // // This is the core of -[LDrawModel optimizeStructure]. // // ============================================================================== public void flattenIntoLines(ArrayList<LDrawLine> lines, ArrayList<LDrawTriangle> triangles, ArrayList<LDrawQuadrilateral> quadrilaterals, ArrayList<LDrawDirective> everythingElse, LDrawColor parentColor, Matrix4 transform, Matrix3 normalTransform, boolean recursive) { // Resolve the correct color and set it. Our subclasses will be // responsible // for then adding themselves to the correct list. // Figure out the actual color of the directive. if (color.colorCode() == LDrawColorT.LDrawCurrentColor) { if (parentColor.colorCode() == LDrawColorT.LDrawCurrentColor) { // just add } else { // set directiveCopy to parent color setLDrawColor(parentColor); } } else if (color.colorCode() == LDrawColorT.LDrawEdgeColor) { if (parentColor.colorCode() == LDrawColorT.LDrawCurrentColor) { // just add } else { // set directiveCopy to compliment color LDrawColor complimentColor = parentColor.complimentColor(); setLDrawColor(complimentColor); // then add. } } else { // This directive is already explicitly colored. Just add. } }// end flattenIntoLines:triangles:quadrilaterals:other:currentColor: }