def _get_layer(layer_name):
    """Get a layer index from the Rhino document from the ladyer name."""
    layer_table = doc.Layers  # layer table
    layer_index = layer_table.Find(layer_name, True)
    if layer_index < 0:
        parent_layer = docobj.Layer()
        parent_layer.Name = layer_name
        layer_index = layer_table.Add(parent_layer)
    return layer_index
Beispiel #2
0
def getAllNormalObjs(bScanForNakedEdges=True):
    rdObjs = []
    settings = rd.ObjectEnumeratorSettings()
    settings.NormalObjects = True
    settings.LockedObjects = False
    for rdObj in sc.doc.Objects.GetObjectList(settings):
        if rdObj.ObjectType == rd.ObjectType.Curve:
            rdObjs.append(rdObj)
        elif rdObj.ObjectType == rd.ObjectType.Brep:
            if bScanForNakedEdges:
                rdObjs.append(rdObj)
    return rdObjs
Beispiel #3
0
def main(bEcho=True, bDebug=False):
    """
    """

    # Custom geometry filter to only select non-NurbsCurve wires.
    def nurbsCurveGeometryFilter(rhObject, geom, compIdx):
        if not isinstance(geom, rg.Curve): return False
        return geom.GetType() == rg.NurbsCurve

    Rhino.RhinoApp.SetCommandPrompt("Searching ...")

    gObjs_Preselected = [
        rdObj.Id
        for rdObj in sc.doc.Objects.GetSelectedObjects(includeLights=False,
                                                       includeGrips=False)
    ]

    gCrvs_Target = []
    iter = rd.ObjectEnumeratorSettings()
    iter.NormalObjects = True
    iter.LockedObjects = False
    iter.IncludeLights = False
    iter.IncludeGrips = False
    for rdRhinoObject in sc.doc.Objects.GetObjectList(iter):
        if rdRhinoObject.Id in gObjs_Preselected:
            continue
        if rdRhinoObject.ObjectType != rd.ObjectType.Curve:
            continue
        rgCrv = rdRhinoObject.CurveGeometry
        sCrvType = rgCrv.GetType().Name
        if sCrvType == 'NurbsCurve':
            if not xKnotList.isUniform(rgCrv.Knots):
                gCrvs_Target.append(rdRhinoObject.Id)
        rgCrv.Dispose()

    ct_Selected = 0

    sc.doc.Views.RedrawEnabled = False
    for gCrv in gCrvs_Target:
        if sc.doc.Objects.Select(gCrv):
            ct_Selected += 1
    sc.doc.Views.RedrawEnabled = True

    if bEcho:
        if gCrvs_Target:
            s = "{} curve{} added to selection.".format(
                ct_Selected, '' if ct_Selected == 1 else 's')
            print s
        else:
            print "\nNo curves added to selection."

    return gCrvs_Target
def _get_layer(layer_name):
    """Get a layer index from the Rhino document from the layer name."""
    layer_table = doc.Layers  # layer table
    layer_index = layer_table.FindByFullPath(layer_name, True)
    if layer_index < 0:
        all_layers = layer_name.split('::')
        parent_name = all_layers[0]
        layer_index = layer_table.FindByFullPath(parent_name, True)
        if layer_index < 0:
            parent_layer = docobj.Layer()
            parent_layer.Name = parent_name
            layer_index = layer_table.Add(parent_layer)
        for lay in all_layers[1:]:
            parent_name = '{}::{}'.format(parent_name, lay)
            parent_index = layer_index
            layer_index = layer_table.FindByFullPath(parent_name, True)
            if layer_index < 0:
                parent_layer = docobj.Layer()
                parent_layer.Name = lay
                parent_layer.ParentLayerId = layer_table[parent_index].Id 
                layer_index = layer_table.Add(parent_layer)
    return layer_index
Beispiel #5
0
 def getAllNormalObjsForSplitters():
     rgCrvs_CrvObjs = []
     rgCrvs_Edges = []
     gBreps_ofEdges = []
     settings = rd.ObjectEnumeratorSettings()
     settings.NormalObjects = True
     settings.LockedObjects = False
     for rdObj in sc.doc.Objects.GetObjectList(settings):
         if rdObj.ObjectType == rd.ObjectType.Curve:
             rgCrvs_CrvObjs.append(rdObj.Geometry)
         elif rdObj.ObjectType == rd.ObjectType.Brep:
             rgNEs = getNakedEdgesOfBrepObject(rdObj)
             for rgNE in rgNEs:
                 rgCrvs_Edges.append(rgNE.DuplicateCurve())
                 gBreps_ofEdges.append(rdObj.Id)
     return rgCrvs_CrvObjs, rgCrvs_Edges, gBreps_ofEdges
def getInput_Curves():
    """
    Get wires with optional input.
    """

    go = ri.Custom.GetObject()

    go.SetCommandPrompt("Select wire curves")
    go.SetCommandPromptDefault("Enter for all normal wires")

    go.GeometryFilter = rd.ObjectType.Curve
    go.GeometryAttributeFilter = ri.Custom.GeometryAttributeFilter.WireCurve

    go.AcceptNothing(True)

    go.AcceptNumber(enable=True, acceptZero=True)

    go.AlreadySelectedObjectSelect = True
    go.DeselectAllBeforePostSelect = False  # So objects won't be deselected on repeats of While loop.
    go.EnableClearObjectsOnEntry(False)
    go.EnableUnselectObjectsOnExit(False)

    idxs_Opts = {}

    while True:
        key = 'fTolerance'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bEcho'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bDebug'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]

        res = go.GetMultiple(minimumNumber=1, maximumNumber=0)

        if res == ri.GetResult.Cancel:
            return
        elif res == ri.GetResult.Nothing:
            rdCrvs = []
            rgEdges = []
            settings = rd.ObjectEnumeratorSettings()
            settings.NormalObjects = True
            settings.LockedObjects = False
            for rdObj in sc.doc.Objects.GetObjectList(settings):
                if rdObj.ObjectType == rd.ObjectType.Curve:
                    rdCrvs.append(rdObj)
            return tuple([rdCrvs + rgEdges] +
                         [Opts.values[key] for key in Opts.keys])
        elif res == ri.GetResult.Object:
            objrefs = go.Objects()
            go.Dispose()
            return tuple([objrefs] + [Opts.values[key] for key in Opts.keys])

        # An option was selected or a number was entered.

        if res == ri.GetResult.Number:
            Opts.riOpts['fTolerance'].CurrentValue = go.Number()

        if Opts.riOpts['fTolerance'].CurrentValue < 0.0:
            Opts.riOpts['fTolerance'].CurrentValue = Opts.riOpts[
                'fTolerance'].InitialValue

        Opts.setValues()
        Opts.saveSticky()
        go.ClearCommandOptions()
def getMatches(objref_toMatch, **kwargs):
    """
    """
    def setOpt(key, value=None):
        if key in kwargs:
            return kwargs[key]
        elif key in Opts.riOpts:
            return Opts.riOpts[key].InitialValue
        else:
            return value

    sAttr = setOpt('sAttr')
    fFloatTol = setOpt('fFloatTol')
    bEcho = setOpt('bEcho')
    bDebug = setOpt('bDebug')

    objref0 = objref_toMatch

    bToMatch_IsExtrusion = bool(objref0.Surface())

    if sAttr == "Colour":
        rdRhObj0 = objref0.Object()

        if rdRhObj0.Attributes.ColorSource == rd.ObjectColorSource.ColorFromMaterial:
            print "Colour from material not supported yet."
            return
        elif rdRhObj0.Attributes.ColorSource == rd.ObjectColorSource.ColorFromObject:
            colorRhObj0 = rdRhObj0.Attributes.ObjectColor
        else:
            if rdRhObj0.Attributes.ColorSource == rd.ObjectColorSource.ColorFromLayer:
                pass
            else:
                # Color from parent.
                # Use layer color unless object is within a block definition.
                pass

            li = rdRhObj0.Attributes.LayerIndex
            layer = sc.doc.Layers.FindIndex(li)
            colorRhObj0 = layer.Color

    elif sAttr == 'Volume':
        rgBrep0 = objref0.Brep(
        )  # Brep is also returned when objref0 contains an Extrusion.

        if not rgBrep0.IsValid:
            print "Reference {} {} is invalid.  Repair it then rerun this script.".format(
                "Extrusion" if bToMatch_IsExtrusion else "Brep",
                objref0.ObjectId)
            rgBrep0.Dispose()
            return

        if not rgBrep0.IsSolid:
            print "Reference {} {} is open.  Its 'Volume' will not be matched.".format(
                "Extrusion" if bToMatch_IsExtrusion else "Brep",
                objref0.ObjectId)
            rgBrep0.Dispose()
            return

        fVol0 = rgBrep0.GetVolume()
        if not fVol0:
            print "Volume can not be calculated.  Repair {} {}.".format(
                "Extrusion" if bToMatch_IsExtrusion else "Brep",
                objref0.ObjectId)
            rgBrep0.Dispose()
            return

        iToMatch_FaceCt = rgBrep0.Faces.Count

        rgBrep0.Dispose()

    gBreps_ToSearch = []
    rgBreps_ToSearch = []
    iCts_Faces_ToSearch = []
    fEdgeLens_ToSearch = []

    iter = rd.ObjectEnumeratorSettings()
    iter.NormalObjects = True
    iter.LockedObjects = False
    iter.IncludeLights = False
    iter.IncludeGrips = False
    iter.ObjectTypeFilter = rd.ObjectType.Brep | rd.ObjectType.Extrusion

    gBreps_MatchesFound = []  # Also can include Extrusions.

    iBrepExtrCt = 0
    for rdObj in sc.doc.Objects.GetObjectList(iter):
        iBrepExtrCt += 1

    iOpenBrepCt = 0

    idxs_AtTenths = [int(round(0.1 * i * iBrepExtrCt, 0)) for i in range(10)]

    for i, rdRhObjX in enumerate(sc.doc.Objects.GetObjectList(iter)):
        if sc.escape_test(throw_exception=False):
            print "*** Analysis interrupted by user." \
                "  Selected breps/extrusions are of partial results."
            return gBreps_MatchesFound

        if rdRhObjX.Id == objref0.ObjectId: continue

        if iBrepExtrCt > 10:
            if i in idxs_AtTenths:
                Rhino.RhinoApp.SetCommandPrompt(
                    "Analysis at {:d}% of {} breps/extrusions ...".format(
                        int(100.0 * (i + 1) / iBrepExtrCt), iBrepExtrCt))
        elif iBrepExtrCt > 1:
            Rhino.RhinoApp.SetCommandPrompt(
                "Analysis at {} of {} breps/extrusions".format(
                    i + 1, iBrepExtrCt))
        else:
            Rhino.RhinoApp.SetCommandPrompt(
                "Analyzing other brep/extrusion ...")

        if sAttr == 'Colour':
            if rdRhObjX.Attributes.ColorSource == rd.ObjectColorSource.ColorFromObject:
                colorRhObjX = rdRhObjX.Attributes.ObjectColor
            elif rdRhObjX.Attributes.ColorSource == rd.ObjectColorSource.ColorFromMaterial:
                print "Colour from material not supported yet."
                return
            else:
                if rdRhObjX.Attributes.ColorSource == rd.ObjectColorSource.ColorFromLayer:
                    pass
                else:
                    # Color from parent.
                    # Use layer color unless object is within a block definition.
                    pass

                li = rdRhObjX.Attributes.LayerIndex
                layer = sc.doc.Layers.FindIndex(li)
                colorRhObjX = layer.Color

            if colorRhObjX == colorRhObj0:
                gBreps_MatchesFound.append(rdRhObjX.Id)
        elif sAttr == 'Name':
            if rdRhObjX.Attributes.Name == objref0.Object().Attributes.Name:
                gBreps_MatchesFound.append(rdRhObjX.Id)
        elif sAttr == 'Layer':
            if rdRhObjX.Attributes.LayerIndex == objref0.Object(
            ).Attributes.LayerIndex:
                gBreps_MatchesFound.append(rdRhObjX.Id)
        elif sAttr == 'Volume':

            bToCheck_IsExtrusion = isinstance(rdRhObjX, rd.ExtrusionObject)

            rgGeomX = rdRhObjX.Geometry

            if not rgGeomX.IsValid:
                print "{} {} is invalid.  Fix first.".format(
                    rdRhObjX.GetType().Name, rdRhObjX.Id)
                rgGeomX.Dispose()
                continue

            if bToCheck_IsExtrusion:
                rgBrepX = rgGeomX.ToBrep(splitKinkyFaces=True)
                rgGeomX.Dispose()
            else:
                rgBrepX = rgGeomX

            if not rgBrepX.IsSolid:
                iOpenBrepCt += 1
                rgBrepX.Dispose()
                continue

            ## This significantly speeds up the analysis.
            #if rdRhObjX.ObjectType == rd.ObjectType.Brep:
            #    if rgBrepX.Faces.Count != iToMatch_FaceCt:
            #        rgBrepX.Dispose()
            #        continue

            fVol = rgBrepX.GetVolume(
            )  # GetVolume may be faster than VolumeMassProperties.Compute.
            if not fVol:
                print "Volume can not be calculated.  Repair {} {}.".format(
                    rdRhObjX.GetType().Name, rdRhObjX.Id)
                rgBrepX.Dispose()
                continue

            rgBrepX.Dispose()

            fVolDiff = abs(fVol - fVol0)
            if bDebug: print "Volume:", fVol0, fVolDiff
            if fVolDiff > fFloatTol:
                continue

            gBreps_MatchesFound.append(rdRhObjX.Id)

    if sAttr == 'Volume':
        if iOpenBrepCt:
            print "{} open breps skipped for volume matching.".format(
                iOpenBrepCt)
        else:
            print "No open breps are present."

    return gBreps_MatchesFound
Beispiel #8
0
def createModifiedFace(rgFace_In, surfaceFunc, bDebug=False):
    """
    Parameters:
        rgFace_In,
        surfaceFunc,
        bDebug,
    Returns on success:
        tuple(
            rg.Brep,
            float(Surface deviation from input))
        str(Feedback)
    Returns on fail:
        None,
        str(Feedback)
    """

    rgB_1F_In = rgFace_In.DuplicateFace(duplicateMeshes=True)
    area_In = rgB_1F_In.GetArea()
    rgB_1F_In.Dispose()
    if area_In <= (10.0 * sc.doc.ModelAbsoluteTolerance)**2:
        return None, "Area of face is too small to process."

    rgSrf_In = rgFace_In.UnderlyingSurface()

    res, sLog = surfaceFunc(rgSrf_In)

    if not res:
        return None, sLog

    ns_Res, srf_dev = res

    if not ns_Res:
        return None, "NurbsSurface not created."
    if not ns_Res.IsValid:
        return None, "Invalid Surface geometry after Fit."

    if rgFace_In.IsSurface:
        rgBrep1_BeforeTrim = ns_Res.ToBrep()
        if not rgBrep1_BeforeTrim.IsValid:
            return None, "Invalid brep geometry after ToBrep."

        # Success.
        return (rgBrep1_BeforeTrim,
                srf_dev), "Trim skipped because face IsSurface."

    rgBrep1_AfterTrim = retrimFace(
        rgFace_In,
        rgSrf_Replacement=
        ns_Res,  # If None, UnderlyingSurface of BrepFace is used.
        rgCrvs_Splitters_Replacement=
        None,  # If None, 3D curves of rgFace loops are used.
        fSplitTol=sc.doc.ModelAbsoluteTolerance,
        bTrimToSegs=True,
        fEdgeLen_Min=2.0 * sc.doc.ModelAbsoluteTolerance,
        bOutputSplitOnFail=False,
        bOutputTrimmingCrvs=False,
        bDebug=bDebug)

    if rgBrep1_AfterTrim is None:
        # Check areas.
        rgBrep1_BeforeTrim = ns_Res.ToBrep()

        area_Out = rgBrep1_BeforeTrim.GetArea()
        area_Diff = abs(area_In - area_Out)
        if area_Diff <= (10.0 * sc.doc.ModelAbsoluteTolerance)**2:
            return (
                rgBrep1_BeforeTrim,
                srf_dev), "Face not trimmed because it is almost IsSurface."

        if bDebug:
            if not rgBrep1_BeforeTrim.IsValid:
                return None, "Invalid brep geometry after ToBrep.  (Split fail)."
            attrRed = rd.ObjectAttributes()
            attrRed.LayerIndex = sc.doc.Layers.CurrentLayerIndex
            attrRed.ColorSource = rd.ObjectColorSource.ColorFromObject
            attrRed.ObjectColor = Color.Red
            gBrep1 = sc.doc.Objects.AddBrep(rgBrep1_BeforeTrim, attrRed)
            if gBrep1 == Guid.Empty:
                return None, "Untrimmed monoface brep could not be added to document."
            return None, "Trim fail.  Split brep added."
        return None, "Trim fail."

    if not rgBrep1_AfterTrim.IsValid:
        if bDebug:
            rgBrep1_BeforeTrim = ns_Res.ToBrep()
            if not rgBrep1_BeforeTrim.IsValid:
                return None, "Invalid brep geometry after ToBrep.  (Split fail)."
            attrRed = rd.ObjectAttributes()
            attrRed.LayerIndex = sc.doc.Layers.CurrentLayerIndex
            attrRed.ColorSource = rd.ObjectColorSource.ColorFromObject
            attrRed.ObjectColor = Color.Red
            gBrep1 = sc.doc.Objects.AddBrep(rgBrep1_BeforeTrim, attrRed)
            if gBrep1 == Guid.Empty:
                return None, "Untrimmed monoface brep could not be added to document."
        return None, "Trim fail."

    # Success.
    return (rgBrep1_AfterTrim, srf_dev), None
def getInput_Curves(objrefs_Face):
    """
    Get curves or edges with optional input.
    """
    def getBrep(rhBrep):
        if isinstance(rhBrep, rg.Brep):
            return None, rhBrep
        elif isinstance(rhBrep, rg.GeometryBase):
            rdObj = None
            rgObj = rhBrep
        elif isinstance(rhBrep, rd.ObjRef):
            rdObj = rhBrep.Object()
            rgObj = rhBrep.Geometry()
        elif isinstance(rhBrep, Guid):
            rdObj = sc.doc.Objects.FindId(
                rhBrep
            ) if Rhino.RhinoApp.ExeVersion >= 6 else sc.doc.Objects.Find(
                rhBrep)
            rgObj = rdObj.Geometry
        else:
            return

        if isinstance(rgObj, (rg.Brep, rg.BrepFace)):
            return rdObj, rgObj

    idxs_EdgesOfFaceToSplit = []
    for objref_Face in objrefs_Face:
        rdBrep_withFaceToSplit, rgBrep_withFaceToSplit = getBrep(objref_Face)
        gBrep_withFaceToSplit = rdBrep_withFaceToSplit.Id
        idxs_EdgesOfFaceToSplit.extend(objref_Face.Face().AdjacentEdges())

    go = ri.Custom.GetObject()

    go.SetCommandPrompt("Select curves or edges")
    go.SetCommandPromptDefault(
        "Enter for all normal wires and brep naked edges")

    go.GeometryFilter = rd.ObjectType.Curve

    def notEdgeOfFaceToSplit(rdObj, geom, compIdx):
        #print rdObj, geom, compIdx
        if isinstance(rdObj,
                      rd.BrepObject) and rdObj.Id == gBrep_withFaceToSplit:
            if geom.EdgeIndex in idxs_EdgesOfFaceToSplit:
                print "An edge of a face to split was picked and will not be used."
                return False
        return True

    go.SetCustomGeometryFilter(notEdgeOfFaceToSplit)

    go.AcceptNothing(True)

    go.AcceptNumber(enable=True, acceptZero=True)

    go.AlreadySelectedObjectSelect = True
    go.DeselectAllBeforePostSelect = False  # So objects won't be deselected on repeats of While loop.
    go.EnableClearObjectsOnEntry(False)
    go.EnableUnselectObjectsOnExit(False)

    idxs_Opts = {}

    while True:
        key = 'bProcessSegs'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bUnderlyingSrf'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'fTolerance'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bCompletelyOnSrfAndClosed'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bCompletelyOnSrfAndOpen'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bPartiallyOnSrf'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'fSamplingResolution'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bAdd'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bEcho'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]
        key = 'bDebug'
        idxs_Opts[key] = Opts.riAddOpts[key](go)[0]

        res = go.GetMultiple(minimumNumber=1, maximumNumber=0)

        if res == ri.GetResult.Cancel:
            return
        elif res == ri.GetResult.Nothing:
            rdCrvs = []
            rgEdges = []
            settings = rd.ObjectEnumeratorSettings()
            settings.NormalObjects = True
            settings.LockedObjects = False
            for rdObj in sc.doc.Objects.GetObjectList(settings):
                if rdObj.ObjectType == rd.ObjectType.Curve:
                    rdCrvs.append(rdObj)
                elif rdObj.ObjectType == rd.ObjectType.Brep:
                    rgBrep = rdObj.BrepGeometry
                    # Structure of following conditional is to optimize speed.
                    if rdObj.Id != gBrep_withFaceToSplit:
                        for edge in rgBrep.Edges:
                            if edge.Valence == rg.EdgeAdjacency.Naked:
                                rgEdges.append(edge)
                    else:
                        for edge in rgBrep.Edges:
                            if edge.EdgeIndex not in idxs_EdgesOfFaceToSplit:
                                if edge.Valence == rg.EdgeAdjacency.Naked:
                                    rgEdges.append(edge)
                            else:
                                if Opts.values['bDebug']:
                                    print "Skipped edge {}.".format(
                                        edge.EdgeIndex)
            return tuple([rdCrvs + rgEdges] +
                         [Opts.values[key] for key in Opts.keys])
        elif res == ri.GetResult.Object:
            objrefs = go.Objects()
            go.Dispose()
            return tuple([objrefs] + [Opts.values[key] for key in Opts.keys])

        # An option was selected or a number was entered.

        if res == ri.GetResult.Number:
            Opts.riOpts['fTolerance'].CurrentValue = go.Number()

        if Opts.riOpts['fTolerance'].CurrentValue < 0.0:
            Opts.riOpts['fTolerance'].CurrentValue = Opts.riOpts[
                'fTolerance'].InitialValue

        Opts.setValues()
        Opts.saveSticky()
        go.ClearCommandOptions()
Beispiel #10
0
def processBrep(rgBrep0,
                idx_rgFaceA,
                idx_rgFaces_Filter=None,
                bTryConvert=None,
                fTolerance=None,
                bShrinkSrfsOfPrimitives=None,
                bEcho=None,
                bDebug=None):
    """
    """

    if bTryConvert is None: bTryConvert = bTryConvert
    if fTolerance is None: fTolerance = Opts.values['fTolerance']
    if bShrinkSrfsOfPrimitives is None:
        bShrinkSrfsOfPrimitives = Opts.values['bShrinkSrfsOfPrimitives']
    if bEcho is None: bEcho = Opts.values['bEcho']
    if bDebug is None: bDebug = Opts.values['bDebug']

    if not rgBrep0.IsManifold:
        if bEcho: print "Brep is non-manifold and will be skipped."
        return

    # Get shape or NurbsSurface of FaceA.
    rgFaceA = rgBrep0.Faces[idx_rgFaceA]
    rgPrimitiveShapeA = None
    rgSrfA = None
    if bTryConvert:
        rc = xPrimitiveShape.BrepFace.tryGetPrimitiveShape(
            rgFace0=rgFaceA, fTolerance=fTolerance, bDebug=bDebug)
        if rc[0] is not None:
            rgPrimitiveShapeA, fTol_Used, sShrunkOrNot = rc[0]
            shapeA = rgPrimitiveShapeA
            idx_rgFs_B0_Merge = xBrep_contiguousCoshapedFaces.getPrimitiveShapedFaces(
                rgFaceA=rgFaceA,
                rgPrimitiveShapeA=rgPrimitiveShapeA,
                idx_rgFaces_Filter=idx_rgFaces_Filter,
                fTolerance=fTolerance,
                bDebug=bDebug)

    if rgPrimitiveShapeA is None:
        rgSrfA = rgFaceA.UnderlyingSurface()
        if not isinstance(rgSrfA, rg.NurbsSurface):
            rgSrfA.Dispose()
            return
        shapeA = rgSrfA
        idx_rgFs_B0_Merge = xBrep_contiguousCoshapedFaces.getNurbsSrfFaces(
            rgFaceA=rgFaceA,
            rgNurbsSurfaceA=rgSrfA,
            idx_rgFaces_Filter=idx_rgFaces_Filter,
            fTolerance=fTolerance,
            bDebug=bDebug)

    if bDebug:
        sEval = 'idx_rgFs_B0_Merge'
        print sEval + ':', eval(sEval)

    if len(idx_rgFs_B0_Merge) < 2:
        if bEcho: print "No matching contiguous faces found for starting face."
        return

    if bEcho:
        s = "Merging to {} ...".format(shapeA.GetType().Name)
        Rhino.RhinoApp.SetCommandPrompt(prompt=s)
        if bDebug: print s

    rgBrep_SubOf0 = rgBrep0.DuplicateSubBrep(faceIndices=idx_rgFs_B0_Merge)

    area0 = rg.Brep.GetArea(rgBrep_SubOf0)
    if not area0:
        if bEcho:
            s = "Area of starting brep {} cannot be calculated".format(gBrep0)
            s += " and will be skipped."
            print s
        return

    if bDebug:
        sEval = 'idx_rgFs_B0_Merge'
        print sEval + ':', eval(sEval)

    rgBrep_New1F = xBrep_createFromShape.replaceShape(rgBrep0=rgBrep_SubOf0,
                                                      shape=shapeA,
                                                      fTolerance=None,
                                                      bDebug=bDebug)
    if rgBrep_New1F is None:
        if bDebug:
            sEval = 'rgBrep_New1F'
            print sEval + ':', eval(sEval)
        return

    # Check old vs. new areas.
    area1 = rg.Brep.GetArea(rgBrep_New1F)
    if not area1:
        if bEcho:
            s = "Area of new brep to replace {}".format(gBrep0)
            s += " cannot be calculated, and this merge will be skipped."
            print s
        return
    percentAreaChange = 100.0 * abs(1.0 - area0 / area1)
    if percentAreaChange > 1.0:
        #if not Rhino.RhinoMath.EpsilonEquals(area0, area1, epsilon=1e-4):
        if bEcho:
            s = "Change in area,"
            s += " {:.6f} of old vs. {:.6f} of new or {:.2g}%.".format(
                area0, area1, percentAreaChange)
            print s
        if bDebug:
            attrRed = rd.ObjectAttributes()
            attrRed.ColorSource = rd.ObjectColorSource.ColorFromObject
            attrRed.ObjectColor = Color.Red
            gBrep1 = sc.doc.Objects.AddBrep(rgBrep_New1F, attrRed)
            if gBrep1 != Guid.Empty:
                print "New, red monoface brep added over old polysurface."
            else:
                print "New monoface brep could not be added for {}".format(
                    gBrep0)
        return

    if bShrinkSrfsOfPrimitives and not isinstance(shapeA, rg.Surface):
        rgBrep_New1F.Faces.ShrinkFaces()

    return rgBrep_New1F, idx_rgFs_B0_Merge