Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

SVGLoader: Implement 'defs' and 'use' nodes #20209

Merged
merged 13 commits into from
Sep 1, 2020
214 changes: 127 additions & 87 deletions examples/js/loaders/SVGLoader.js
Original file line number Diff line number Diff line change
Expand Up @@ -59,6 +59,8 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype

var transform = getNodeTransform( node );

var traverseChildNodes = true;

var path = null;

switch ( node.nodeName ) {
Expand Down Expand Up @@ -109,6 +111,24 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
path = parseLineNode( node );
break;

case 'defs':
traverseChildNodes = false;
break;

case 'use':
style = parseStyle( node, style );
var usedNodeId = node.href.baseVal.substring( 1 );
var usedNode = node.viewportElement.getElementById( usedNodeId );
if ( usedNode ) {

parseNode( usedNode, style );

}
else console.warn( "SVGLoader: 'use node' references non-existent node id: " + usedNodeId );
break;

break;

default:
// console.log( node );

Expand All @@ -130,11 +150,15 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype

}

var nodes = node.childNodes;
if ( traverseChildNodes ) {

var nodes = node.childNodes;

for ( var i = 0; i < nodes.length; i ++ ) {
for ( var i = 0; i < nodes.length; i ++ ) {

parseNode( nodes[ i ], style );
parseNode( nodes[ i ], style );

}

}

Expand Down Expand Up @@ -641,13 +665,13 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
rx = Math.abs( rx );
ry = Math.abs( ry );

// Compute (x1, y1)
// Compute (x1', y1')
var dx2 = ( start.x - end.x ) / 2.0;
var dy2 = ( start.y - end.y ) / 2.0;
var x1p = Math.cos( x_axis_rotation ) * dx2 + Math.sin( x_axis_rotation ) * dy2;
var y1p = - Math.sin( x_axis_rotation ) * dx2 + Math.cos( x_axis_rotation ) * dy2;

// Compute (cx, cy)
// Compute (cx', cy')
var rxs = rx * rx;
var rys = ry * ry;
var x1ps = x1p * x1p;
Expand All @@ -674,11 +698,11 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype
var cxp = q * rx * y1p / ry;
var cyp = - q * ry * x1p / rx;

// Step 3: Compute (cx, cy) from (cx′, cy′)
// Step 3: Compute (cx, cy) from (cx′, cy′)
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔

var cx = Math.cos( x_axis_rotation ) * cxp - Math.sin( x_axis_rotation ) * cyp + ( start.x + end.x ) / 2;
var cy = Math.sin( x_axis_rotation ) * cxp + Math.cos( x_axis_rotation ) * cyp + ( start.y + end.y ) / 2;

// Step 4: Compute θ1 and Δθ
// Step 4: Compute θ1 and Δθ
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🤔

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

What codification should have the source .js files? UTF-8 or other?

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Should be UTF-8. Maybe modularize.js doesn't currently support that?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe modularize.js doesn't currently support that?

But the problem is in the .js, not the jsm.

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just tested, and modularize seems to behave correctly.

var theta = svgAngle( 1, 0, ( x1p - cxp ) / rx, ( y1p - cyp ) / ry );
var delta = svgAngle( ( x1p - cxp ) / rx, ( y1p - cyp ) / ry, ( - x1p - cxp ) / rx, ( - y1p - cyp ) / ry ) % ( Math.PI * 2 );

Expand Down Expand Up @@ -887,6 +911,8 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype

if ( adjustFunction === undefined ) adjustFunction = function copy( v ) {

if ( v.startsWith( 'url' ) ) console.warn( "SVGLoader: url access in attributes is not implemented." );

return v;

};
Expand Down Expand Up @@ -1069,7 +1095,7 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype

function getNodeTransform( node ) {

if ( ! node.hasAttribute( 'transform' ) ) {
if ( ! ( node.hasAttribute( 'transform' ) || ( node.nodeName === 'use' && ( node.hasAttribute( 'x' ) || node.hasAttribute( 'y' ) ) ) ) ) {

return null;

Expand All @@ -1092,144 +1118,158 @@ THREE.SVGLoader.prototype = Object.assign( Object.create( THREE.Loader.prototype

function parseNodeTransform( node ) {

var transform = new THREE.Matrix3();
var transform = new Matrix3();
Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Does this work?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

My mistake. Fixed.

Copy link
Owner

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Hmm, are you sure it's fixed?

Copy link
Collaborator Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Sorry, I must have failed to git add it.

var currentTransform = tempTransform0;
var transformsTexts = node.getAttribute( 'transform' ).split( ')' );

for ( var tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex -- ) {
if ( node.nodeName === 'use' && ( node.hasAttribute( 'x' ) || node.hasAttribute( 'y' ) ) ) {

var tx = parseFloatWithUnits( node.getAttribute( 'x' ) );
var ty = parseFloatWithUnits( node.getAttribute( 'y' ) );

var transformText = transformsTexts[ tIndex ].trim();
transform.translate( tx, ty );

if ( transformText === '' ) continue;
}

var openParPos = transformText.indexOf( '(' );
var closeParPos = transformText.length;
if ( node.hasAttribute( 'transform' ) ) {

if ( openParPos > 0 && openParPos < closeParPos ) {
var transformsTexts = node.getAttribute( 'transform' ).split( ')' );

var transformType = transformText.substr( 0, openParPos );
for ( var tIndex = transformsTexts.length - 1; tIndex >= 0; tIndex -- ) {

var array = parseFloats( transformText.substr( openParPos + 1, closeParPos - openParPos - 1 ) );
var transformText = transformsTexts[ tIndex ].trim();

currentTransform.identity();
if ( transformText === '' ) continue;

var openParPos = transformText.indexOf( '(' );
var closeParPos = transformText.length;

if ( openParPos > 0 && openParPos < closeParPos ) {

var transformType = transformText.substr( 0, openParPos );

var array = parseFloats( transformText.substr( openParPos + 1, closeParPos - openParPos - 1 ) );

currentTransform.identity();

switch ( transformType ) {

switch ( transformType ) {
case "translate":

case "translate":
if ( array.length >= 1 ) {

if ( array.length >= 1 ) {
var tx = array[ 0 ];
var ty = tx;

var tx = array[ 0 ];
var ty = tx;
if ( array.length >= 2 ) {

if ( array.length >= 2 ) {
ty = array[ 1 ];

ty = array[ 1 ];
}

currentTransform.translate( tx, ty );

}

currentTransform.translate( tx, ty );
break;

}
case "rotate":

break;
if ( array.length >= 1 ) {

case "rotate":
var angle = 0;
var cx = 0;
var cy = 0;

if ( array.length >= 1 ) {
// Angle
angle = - array[ 0 ] * Math.PI / 180;

var angle = 0;
var cx = 0;
var cy = 0;
if ( array.length >= 3 ) {

// Angle
angle = - array[ 0 ] * Math.PI / 180;
// Center x, y
cx = array[ 1 ];
cy = array[ 2 ];

if ( array.length >= 3 ) {
}

// Center x, y
cx = array[ 1 ];
cy = array[ 2 ];
// Rotate around center (cx, cy)
tempTransform1.identity().translate( - cx, - cy );
tempTransform2.identity().rotate( angle );
tempTransform3.multiplyMatrices( tempTransform2, tempTransform1 );
tempTransform1.identity().translate( cx, cy );
currentTransform.multiplyMatrices( tempTransform1, tempTransform3 );

}

// Rotate around center (cx, cy)
tempTransform1.identity().translate( - cx, - cy );
tempTransform2.identity().rotate( angle );
tempTransform3.multiplyMatrices( tempTransform2, tempTransform1 );
tempTransform1.identity().translate( cx, cy );
currentTransform.multiplyMatrices( tempTransform1, tempTransform3 );
break;

}
case "scale":

break;
if ( array.length >= 1 ) {

case "scale":
var scaleX = array[ 0 ];
var scaleY = scaleX;

if ( array.length >= 1 ) {
if ( array.length >= 2 ) {

var scaleX = array[ 0 ];
var scaleY = scaleX;
scaleY = array[ 1 ];

if ( array.length >= 2 ) {
}

scaleY = array[ 1 ];
currentTransform.scale( scaleX, scaleY );

}

currentTransform.scale( scaleX, scaleY );
break;

}
case "skewX":

break;
if ( array.length === 1 ) {

case "skewX":
currentTransform.set(
1, Math.tan( array[ 0 ] * Math.PI / 180 ), 0,
0, 1, 0,
0, 0, 1
);

if ( array.length === 1 ) {
}

currentTransform.set(
1, Math.tan( array[ 0 ] * Math.PI / 180 ), 0,
0, 1, 0,
0, 0, 1
);
break;

}
case "skewY":

break;
if ( array.length === 1 ) {

case "skewY":
currentTransform.set(
1, 0, 0,
Math.tan( array[ 0 ] * Math.PI / 180 ), 1, 0,
0, 0, 1
);

if ( array.length === 1 ) {
}

currentTransform.set(
1, 0, 0,
Math.tan( array[ 0 ] * Math.PI / 180 ), 1, 0,
0, 0, 1
);
break;

}
case "matrix":

break;
if ( array.length === 6 ) {

case "matrix":
currentTransform.set(
array[ 0 ], array[ 2 ], array[ 4 ],
array[ 1 ], array[ 3 ], array[ 5 ],
0, 0, 1
);

if ( array.length === 6 ) {
}

currentTransform.set(
array[ 0 ], array[ 2 ], array[ 4 ],
array[ 1 ], array[ 3 ], array[ 5 ],
0, 0, 1
);
break;

}

break;
}

}

}
transform.premultiply( currentTransform );

transform.premultiply( currentTransform );
}

}

Expand Down
Loading