Kaynağa Gözat

add multipleBonds param to bond visuals

Alexander Rose 3 yıl önce
ebeveyn
işleme
dcaf6f8927

+ 1 - 0
CHANGELOG.md

@@ -14,6 +14,7 @@ Note that since we don't clearly distinguish between a public and private interf
     - Add ``preferAtomPixelPadding`` to Canvas3dInteractionHelper
 - Add points & crosses visuals to Line representation
 - Add ``pickPadding`` config option (look around in case target pixel is empty)
+- Add ``multipleBonds`` param to bond visuals with options: off, symmetric, offset
 
 ## [v2.3.3] - 2021-10-01
 

+ 1 - 0
src/mol-repr/structure/representation/line.ts

@@ -29,6 +29,7 @@ export const LineParams = {
     ...InterUnitBondLineParams,
     ...ElementPointParams,
     ...ElementCrossParams,
+    multipleBonds: PD.Select('offset', PD.arrayToOptions(['off', 'symmetric', 'offset'] as const)),
     includeParent: PD.Boolean(false),
     sizeFactor: PD.Numeric(3, { min: 0.01, max: 10, step: 0.01 }),
     unitKinds: getUnitKindsParam(['atomic']),

+ 14 - 7
src/mol-repr/structure/visual/bond-inter-unit-cylinder.ts

@@ -40,7 +40,10 @@ function getInterUnitBondCylinderBuilderProps(structure: Structure, theme: Theme
 
     const bonds = structure.interUnitBonds;
     const { edgeCount, edges } = bonds;
-    const { sizeFactor, sizeAspectRatio, adjustCylinderLength, aromaticBonds } = props;
+    const { sizeFactor, sizeAspectRatio, adjustCylinderLength, aromaticBonds, multipleBonds } = props;
+
+    const mbOff = multipleBonds === 'off';
+    const mbSymmetric = multipleBonds === 'symmetric';
 
     const delta = Vec3();
 
@@ -136,14 +139,16 @@ function getInterUnitBondCylinderBuilderProps(structure: Structure, theme: Theme
                 // show metallic coordinations and hydrogen bonds with dashed cylinders
                 return LinkStyle.Dashed;
             } else if (o === 3) {
-                return LinkStyle.Triple;
+                return mbOff ? LinkStyle.Solid :
+                    mbSymmetric ? LinkStyle.Triple :
+                        LinkStyle.OffsetTriple;
             } else if (aromaticBonds && BondType.is(f, BondType.Flag.Aromatic)) {
                 return LinkStyle.Aromatic;
-            } else if (o === 2) {
-                return LinkStyle.Double;
             }
 
-            return LinkStyle.Solid;
+            return (o !== 2 || mbOff) ? LinkStyle.Solid :
+                mbSymmetric ? LinkStyle.Double :
+                    LinkStyle.OffsetDouble;
         },
         radius: (edgeIndex: number) => {
             return radius(edgeIndex) * sizeAspectRatio;
@@ -216,7 +221,8 @@ export function InterUnitBondCylinderImpostorVisual(materialId: number): Complex
                 newProps.stubCap !== currentProps.stubCap ||
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
-                newProps.adjustCylinderLength !== currentProps.adjustCylinderLength
+                newProps.adjustCylinderLength !== currentProps.adjustCylinderLength ||
+                newProps.multipleBonds !== currentProps.multipleBonds
             );
 
             if (newStructure.interUnitBonds !== currentStructure.interUnitBonds) {
@@ -254,7 +260,8 @@ export function InterUnitBondCylinderMeshVisual(materialId: number): ComplexVisu
                 newProps.stubCap !== currentProps.stubCap ||
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
-                newProps.adjustCylinderLength !== currentProps.adjustCylinderLength
+                newProps.adjustCylinderLength !== currentProps.adjustCylinderLength ||
+                newProps.multipleBonds !== currentProps.multipleBonds
             );
 
             if (newStructure.interUnitBonds !== currentStructure.interUnitBonds) {

+ 13 - 6
src/mol-repr/structure/visual/bond-inter-unit-line.ts

@@ -32,10 +32,14 @@ function setRefPosition(pos: Vec3, structure: Structure, unit: Unit.Atomic, inde
 function createInterUnitBondLines(ctx: VisualContext, structure: Structure, theme: Theme, props: PD.Values<InterUnitBondLineParams>, lines?: Lines) {
     const bonds = structure.interUnitBonds;
     const { edgeCount, edges } = bonds;
-    const { sizeFactor, aromaticBonds } = props;
 
     if (!edgeCount) return Lines.createEmpty(lines);
 
+    const { sizeFactor, aromaticBonds, multipleBonds } = props;
+
+    const mbOff = multipleBonds === 'off';
+    const mbSymmetric = multipleBonds === 'symmetric';
+
     const ref = Vec3();
     const loc = StructureElement.Location.create();
 
@@ -74,14 +78,16 @@ function createInterUnitBondLines(ctx: VisualContext, structure: Structure, them
                 // show metallic coordinations and hydrogen bonds with dashed cylinders
                 return LinkStyle.Dashed;
             } else if (o === 3) {
-                return LinkStyle.Triple;
+                return mbOff ? LinkStyle.Solid :
+                    mbSymmetric ? LinkStyle.Triple :
+                        LinkStyle.OffsetTriple;
             } else if (aromaticBonds && BondType.is(f, BondType.Flag.Aromatic)) {
                 return LinkStyle.Aromatic;
-            } else if (o === 2) {
-                return LinkStyle.Double;
             }
 
-            return LinkStyle.Solid;
+            return (o !== 2 || mbOff) ? LinkStyle.Solid :
+                mbSymmetric ? LinkStyle.Double :
+                    LinkStyle.OffsetDouble;
         },
         radius: (edgeIndex: number) => {
             const b = edges[edgeIndex];
@@ -128,7 +134,8 @@ export function InterUnitBondLineVisual(materialId: number): ComplexVisual<Inter
                 newProps.dashCount !== currentProps.dashCount ||
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
-                !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes)
+                !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
+                newProps.multipleBonds !== currentProps.multipleBonds
             );
 
             if (newStructure.interUnitBonds !== currentStructure.interUnitBonds) {

+ 14 - 5
src/mol-repr/structure/visual/bond-intra-unit-cylinder.ts

@@ -33,7 +33,10 @@ function getIntraUnitBondCylinderBuilderProps(unit: Unit.Atomic, structure: Stru
     const bonds = unit.bonds;
     const { edgeCount, a, b, edgeProps, offset } = bonds;
     const { order: _order, flags: _flags } = edgeProps;
-    const { sizeFactor, sizeAspectRatio, adjustCylinderLength, aromaticBonds, includeTypes, excludeTypes } = props;
+    const { sizeFactor, sizeAspectRatio, adjustCylinderLength, aromaticBonds, includeTypes, excludeTypes, multipleBonds } = props;
+
+    const mbOff = multipleBonds === 'off';
+    const mbSymmetric = multipleBonds === 'symmetric';
 
     const include = BondType.fromNames(includeTypes);
     const exclude = BondType.fromNames(excludeTypes);
@@ -130,7 +133,9 @@ function getIntraUnitBondCylinderBuilderProps(unit: Unit.Atomic, structure: Stru
                 // show metallic coordinations and hydrogen bonds with dashed cylinders
                 return LinkStyle.Dashed;
             } else if (o === 3) {
-                return LinkStyle.Triple;
+                return mbOff ? LinkStyle.Solid :
+                    mbSymmetric ? LinkStyle.Triple :
+                        LinkStyle.OffsetTriple;
             } else if (aromaticBonds) {
                 const aI = a[edgeIndex], bI = b[edgeIndex];
                 const aR = elementAromaticRingIndices.get(aI);
@@ -146,7 +151,9 @@ function getIntraUnitBondCylinderBuilderProps(unit: Unit.Atomic, structure: Stru
                 }
             }
 
-            return o === 2 ? LinkStyle.Double : LinkStyle.Solid;
+            return (o !== 2 || mbOff) ? LinkStyle.Solid :
+                mbSymmetric ? LinkStyle.Double :
+                    LinkStyle.OffsetDouble;
         },
         radius: (edgeIndex: number) => {
             return radius(edgeIndex) * sizeAspectRatio;
@@ -228,7 +235,8 @@ export function IntraUnitBondCylinderImpostorVisual(materialId: number): UnitsVi
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
                 newProps.adjustCylinderLength !== currentProps.adjustCylinderLength ||
-                newProps.aromaticBonds !== currentProps.aromaticBonds
+                newProps.aromaticBonds !== currentProps.aromaticBonds ||
+                newProps.multipleBonds !== currentProps.multipleBonds
             );
 
             const newUnit = newStructureGroup.group.units[0];
@@ -271,7 +279,8 @@ export function IntraUnitBondCylinderMeshVisual(materialId: number): UnitsVisual
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
                 newProps.adjustCylinderLength !== currentProps.adjustCylinderLength ||
-                newProps.aromaticBonds !== currentProps.aromaticBonds
+                newProps.aromaticBonds !== currentProps.aromaticBonds ||
+                newProps.multipleBonds !== currentProps.multipleBonds
             );
 
             const newUnit = newStructureGroup.group.units[0];

+ 12 - 4
src/mol-repr/structure/visual/bond-intra-unit-line.ts

@@ -39,7 +39,10 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
     if (!edgeCount) return Lines.createEmpty(lines);
 
     const { order: _order, flags: _flags } = edgeProps;
-    const { sizeFactor, aromaticBonds, includeTypes, excludeTypes } = props;
+    const { sizeFactor, aromaticBonds, includeTypes, excludeTypes, multipleBonds } = props;
+
+    const mbOff = multipleBonds === 'off';
+    const mbSymmetric = multipleBonds === 'symmetric';
 
     const include = BondType.fromNames(includeTypes);
     const exclude = BondType.fromNames(excludeTypes);
@@ -91,7 +94,9 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
                 // show metallic coordinations and hydrogen bonds with dashed cylinders
                 return LinkStyle.Dashed;
             } else if (o === 3) {
-                return LinkStyle.Triple;
+                return mbOff ? LinkStyle.Solid :
+                    mbSymmetric ? LinkStyle.Triple :
+                        LinkStyle.OffsetTriple;
             } else if (aromaticBonds) {
                 const aI = a[edgeIndex], bI = b[edgeIndex];
                 const aR = elementAromaticRingIndices.get(aI);
@@ -107,7 +112,9 @@ function createIntraUnitBondLines(ctx: VisualContext, unit: Unit, structure: Str
                 }
             }
 
-            return o === 2 ? LinkStyle.Double : LinkStyle.Solid;
+            return (o !== 2 || mbOff) ? LinkStyle.Solid :
+                mbSymmetric ? LinkStyle.Double :
+                    LinkStyle.OffsetDouble;
         },
         radius: (edgeIndex: number) => {
             location.element = elements[a[edgeIndex]];
@@ -150,7 +157,8 @@ export function IntraUnitBondLineVisual(materialId: number): UnitsVisual<IntraUn
                 newProps.ignoreHydrogens !== currentProps.ignoreHydrogens ||
                 !arrayEqual(newProps.includeTypes, currentProps.includeTypes) ||
                 !arrayEqual(newProps.excludeTypes, currentProps.excludeTypes) ||
-                newProps.aromaticBonds !== currentProps.aromaticBonds
+                newProps.aromaticBonds !== currentProps.aromaticBonds ||
+                newProps.multipleBonds !== currentProps.multipleBonds
             );
 
             const newUnit = newStructureGroup.group.units[0];

+ 1 - 0
src/mol-repr/structure/visual/util/bond.ts

@@ -20,6 +20,7 @@ export const BondParams = {
     excludeTypes: PD.MultiSelect([] as BondType.Names[], PD.objectToOptions(BondType.Names)),
     ignoreHydrogens: PD.Boolean(false),
     aromaticBonds: PD.Boolean(false, { description: 'Display aromatic bonds with dashes' }),
+    multipleBonds: PD.Select('symmetric', PD.arrayToOptions(['off', 'symmetric', 'offset'] as const)),
 };
 export const DefaultBondProps = PD.getDefaultValues(BondParams);
 export type BondProps = typeof DefaultBondProps

+ 68 - 18
src/mol-repr/structure/visual/util/link.ts

@@ -83,10 +83,12 @@ export const enum LinkStyle {
     Solid = 0,
     Dashed = 1,
     Double = 2,
-    Triple = 3,
-    Disk = 4,
-    Aromatic = 5,
-    MirroredAromatic = 6,
+    OffsetDouble = 3,
+    Triple = 4,
+    OffsetTriple = 5,
+    Disk = 6,
+    Aromatic = 7,
+    MirroredAromatic = 8,
 }
 
 // avoiding namespace lookup improved performance in Chrome (Aug 2020)
@@ -128,14 +130,16 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
 
         position(va, vb, edgeIndex);
         v3sub(tmpV12, vb, va);
+        const dirFlag = v3dot(tmpV12, up) > 0;
 
         const linkRadius = radius(edgeIndex);
         const linkStyle = style ? style(edgeIndex) : LinkStyle.Solid;
         const linkStub = stubCap && (stub ? stub(edgeIndex) : false);
-        const [topCap, bottomCap] = (v3dot(tmpV12, up) > 0) ? [linkStub, linkCap] : [linkCap, linkStub];
+        const [topCap, bottomCap] = dirFlag ? [linkStub, linkCap] : [linkCap, linkStub];
         builderState.currentGroup = edgeIndex;
 
-        const aromaticOffsetFactor = 4.5;
+        const aromaticOffsetFactor = 5.5;
+        const multipleOffsetFactor = 4;
 
         if (linkStyle === LinkStyle.Solid) {
             cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
@@ -148,9 +152,9 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
             cylinderProps.topCap = cylinderProps.bottomCap = dashCap;
 
             addFixedCountDashedCylinder(builderState, va, vb, 0.5, segmentCount, cylinderProps);
-        } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
-            const order = linkStyle === LinkStyle.Double ? 2 :
-                linkStyle === LinkStyle.Triple ? 3 : 1.5;
+        } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
+            const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 :
+                linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5;
             const multiRadius = linkRadius * (linkScale / (0.5 * order));
             const absOffset = (linkRadius - multiRadius) * linkSpacing;
 
@@ -176,6 +180,30 @@ export function createLinkCylinderMesh(ctx: VisualContext, linkBuilder: LinkBuil
                     v3add(vb, vb, vShift);
                     addFixedCountDashedCylinder(builderState, va, vb, 0.5, 3, cylinderProps);
                 }
+            } else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
+                v3setMagnitude(vShift, vShift, absOffset);
+
+                cylinderProps.radiusTop = cylinderProps.radiusBottom = linkRadius;
+                addCylinder(builderState, va, vb, 0.5, cylinderProps);
+
+                v3scale(tmpV12, tmpV12, linkSpacing * linkScale * 0.2);
+                v3add(va, va, tmpV12);
+                v3sub(vb, vb, tmpV12);
+
+                cylinderProps.radiusTop = cylinderProps.radiusBottom = multiRadius;
+                cylinderProps.topCap = dirFlag ? linkStub : dashCap;
+                cylinderProps.bottomCap = dirFlag ? dashCap : linkStub;
+                v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor);
+                v3sub(va, va, vShift);
+                v3sub(vb, vb, vShift);
+                addCylinder(builderState, va, vb, 0.5, cylinderProps);
+
+                if (order === 3) {
+                    v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor * 2);
+                    v3add(va, va, vShift);
+                    v3add(vb, vb, vShift);
+                    addCylinder(builderState, va, vb, 0.5, cylinderProps);
+                }
             } else {
                 v3setMagnitude(vShift, vShift, absOffset);
 
@@ -224,7 +252,8 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
 
     const aromaticSegmentCount = 3;
     const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount);
-    const aromaticOffsetFactor = 4.5;
+    const aromaticOffsetFactor = 5.5;
+    const multipleOffsetFactor = 4;
 
     for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) {
         if (ignore && ignore(edgeIndex)) continue;
@@ -242,9 +271,9 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
             v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
             v3sub(vb, vb, tmpV12);
             builder.addFixedCountDashes(va, vb, segmentCount, dashScale, dashCap, dashCap, edgeIndex);
-        } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
-            const order = linkStyle === LinkStyle.Double ? 2 :
-                linkStyle === LinkStyle.Triple ? 3 : 1.5;
+        } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
+            const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 :
+                linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5;
             const multiScale = linkScale / (0.5 * order);
             const absOffset = (linkRadius - multiScale * linkRadius) * linkSpacing;
 
@@ -268,10 +297,20 @@ export function createLinkCylinderImpostors(ctx: VisualContext, linkBuilder: Lin
                     v3add(vb, vb, vShift);
                     builder.addFixedCountDashes(va, vb, aromaticSegmentCount, linkScale, dashCap, dashCap, edgeIndex);
                 }
+            } else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
+                v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor);
+
+                builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], 1, linkCap, linkStub, edgeIndex);
+
+                v3scale(tmpV12, v3sub(tmpV12, va, vb), linkSpacing * linkScale * 0.2);
+                v3sub(va, va, tmpV12);
+
+                if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
+                builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, dashCap, linkStub, edgeIndex);
             } else {
                 v3setMagnitude(vShift, vShift, absOffset);
 
-                if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], multiScale, linkCap, false, edgeIndex);
+                if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], multiScale, linkCap, linkStub, edgeIndex);
                 builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], multiScale, linkCap, linkStub, edgeIndex);
                 builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], multiScale, linkCap, linkStub, edgeIndex);
             }
@@ -313,6 +352,7 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
     const aromaticSegmentCount = 3;
     const aromaticLengthScale = 0.5 - (0.5 / 2 / aromaticSegmentCount);
     const aromaticOffsetFactor = 4.5;
+    const multipleOffsetFactor = 3;
 
     for (let edgeIndex = 0, _eI = linkCount; edgeIndex < _eI; ++edgeIndex) {
         if (ignore && ignore(edgeIndex)) continue;
@@ -328,9 +368,9 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
             v3scale(tmpV12, v3sub(tmpV12, vb, va), lengthScale);
             v3sub(vb, vb, tmpV12);
             builder.addFixedCountDashes(va, vb, segmentCount, edgeIndex);
-        } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
-            const order = linkStyle === LinkStyle.Double ? 2 :
-                linkStyle === LinkStyle.Triple ? 3 : 1.5;
+        } else if (linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple || linkStyle === LinkStyle.Aromatic || linkStyle === LinkStyle.MirroredAromatic) {
+            const order = linkStyle === LinkStyle.Double || linkStyle === LinkStyle.OffsetDouble ? 2 :
+                linkStyle === LinkStyle.Triple || linkStyle === LinkStyle.OffsetTriple ? 3 : 1.5;
             const multiRadius = 1 * (linkScale / (0.5 * order));
             const absOffset = (1 - multiRadius) * linkSpacing;
 
@@ -354,8 +394,18 @@ export function createLinkLines(ctx: VisualContext, linkBuilder: LinkBuilderProp
                     v3add(vb, vb, vShift);
                     builder.addFixedCountDashes(va, vb, aromaticSegmentCount, edgeIndex);
                 }
+            } else if (linkStyle === LinkStyle.OffsetDouble || linkStyle === LinkStyle.OffsetTriple) {
+                v3setMagnitude(vShift, vShift, absOffset * multipleOffsetFactor);
+
+                builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
+
+                v3scale(tmpV12, v3sub(tmpV12, va, vb), linkSpacing * linkScale);
+                v3sub(va, va, tmpV12);
+
+                if (order === 3) builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], edgeIndex);
+                builder.add(va[0] - vShift[0], va[1] - vShift[1], va[2] - vShift[2], vm[0] - vShift[0], vm[1] - vShift[1], vm[2] - vShift[2], edgeIndex);
             } else {
-                v3setMagnitude(vShift, vShift, absOffset);
+                v3setMagnitude(vShift, vShift, absOffset * 1.5);
 
                 if (order === 3) builder.add(va[0], va[1], va[2], vm[0], vm[1], vm[2], edgeIndex);
                 builder.add(va[0] + vShift[0], va[1] + vShift[1], va[2] + vShift[2], vm[0] + vShift[0], vm[1] + vShift[1], vm[2] + vShift[2], edgeIndex);